Ejemplo n.º 1
0
        public static DocumentSchema Load(TextReader reader, string title)
        {
            using (var json = new JsonTextReader(reader))
            {
                DocumentSchema schema;
                try
                {
                    schema = DefaultSerializer.Value.Deserialize <DocumentSchema>(json);
                }
                catch (Exception e)
                {
                    throw new InvalidSchemaException($"Not a valid schema: {e.Message}", e);
                }

                SchemaValidator.Validate(schema);

                if (string.IsNullOrWhiteSpace(schema.Title))
                {
                    if (string.IsNullOrWhiteSpace(title))
                    {
                        throw new InvalidSchemaException($"Title of schema must be specified.");
                    }
                    schema.Title = title;
                }

                if (schema.Type != JSchemaType.Object)
                {
                    throw new InvalidSchemaException("Type for the root schema object must be object");
                }

                if (!JsonPointer.TryCreate(schema.Metadata, out var pointer))
                {
                    throw new InvalidJsonPointerException($"Metadata's json pointer {schema.Metadata} is invalid.");
                }

                var metadataSchema = pointer.FindSchema(schema);
                if (metadataSchema != null && metadataSchema.Type != JSchemaType.Object)
                {
                    throw new InvalidJsonPointerException($"The referenced object is in type: {metadataSchema.Type}, only object can be a metadata reference");
                }

                schema.MetadataReference = pointer;

                return(schema);
            }
        }
Ejemplo n.º 2
0
        public static DocumentSchema Load(TextReader reader, string title)
        {
            DocumentSchema schema;

            using var jtr = new JsonTextReader(reader);
            JSchema jSchema;
            JObject jObject;

            try
            {
                jObject = JObject.Load(jtr);
                jSchema = JSchema.Load(jObject.CreateReader());
            }
            catch (Exception e) when(e is JSchemaException || e is JsonException)
            {
                var message = ($"{title} is not a valid schema: {e.Message}");

                Logger.LogError(message, code: ErrorCodes.Build.ViolateSchema);
                throw new InvalidSchemaException(message, e);
            }

            var validator = new SchemaValidator(jObject, jSchema);

            // validate schema here
            validator.ValidateMetaSchema();

            try
            {
                schema = LoadSchema <DocumentSchema>(jSchema, new Dictionary <JSchema, BaseSchema>());
                schema.SchemaVersion = jSchema.SchemaVersion;
                schema.Id            = jSchema.Id;
                schema.Version       = GetValueFromJSchemaExtensionData <string>(jSchema, "version");
                schema.Metadata      = GetValueFromJSchemaExtensionData <string>(jSchema, "metadata");
                schema.Validator     = validator;
            }
            catch (Exception e)
            {
                var message = $"{title} is not a valid schema: {e.Message}";
                Logger.LogError(message, code: ErrorCodes.Build.ViolateSchema);
                throw new InvalidSchemaException(message, e);
            }

            if (string.IsNullOrWhiteSpace(schema.Title))
            {
                if (string.IsNullOrWhiteSpace(title))
                {
                    var message = "Title of schema must be specified.";
                    Logger.LogError(message, code: ErrorCodes.Build.ViolateSchema);
                    throw new InvalidSchemaException(message);
                }
                schema.Title = title;
            }

            if (schema.Type != JSchemaType.Object)
            {
                var message = "Type for the root schema object must be object";
                Logger.LogError(message, code: ErrorCodes.Build.ViolateSchema);
                throw new InvalidSchemaException(message);
            }

            if (!JsonPointer.TryCreate(schema.Metadata, out var pointer))
            {
                var message = $"Metadata's json pointer {schema.Metadata} is invalid.";
                Logger.LogError(message, code: ErrorCodes.Build.ViolateSchema);
                throw new InvalidSchemaException(message);
            }

            var metadataSchema = pointer.FindSchema(schema);

            if (metadataSchema != null && metadataSchema.Type != JSchemaType.Object)
            {
                throw new InvalidJsonPointerException($"The referenced object is in type: {metadataSchema.Type}, only object can be a metadata reference");
            }

            schema.MetadataReference = pointer;
            schema.AllowOverwrite    = CheckOverwriteAbility(schema);
            schema.Hash = JsonUtility.Serialize(jObject).GetMd5String();

            return(schema);
        }
Ejemplo n.º 3
0
        private void ApplyOverwriteToModel(OverwriteApplier overwriteApplier, string uid, IHostService host)
        {
            var ms       = host.LookupByUid(uid);
            var ods      = ms.Where(m => m.Type == DocumentType.Overwrite).ToList();
            var articles = ms.Except(ods).ToList();

            if (articles.Count == 0 || ods.Count == 0)
            {
                return;
            }

            if (articles.Count > 1)
            {
                throw new DocumentException($"{uid} is defined in multiple articles {articles.Select(s => s.LocalPathFromRoot).ToDelimitedString()}");
            }

            var model  = articles[0];
            var schema = model.Properties.Schema as DocumentSchema;

            using (new LoggerFileScope(model.LocalPathFromRoot))
            {
                var uidDefiniton = model.Uids.Where(s => s.Name == uid).ToList();
                if (uidDefiniton.Count == 0)
                {
                    throw new DocfxException($"Unable to find UidDefinition for Uid {uid}");
                }

                try
                {
                    foreach (var ud in uidDefiniton)
                    {
                        var jsonPointer         = new JsonPointer(ud.Path).GetParentPointer();
                        var schemaForCurrentUid = jsonPointer.FindSchema(schema);
                        var source = jsonPointer.GetValue(model.Content);

                        foreach (var od in ods)
                        {
                            using (new LoggerFileScope(od.LocalPathFromRoot))
                            {
                                foreach (var fm in ((IEnumerable <OverwriteDocumentModel>)od.Content).Where(s => s.Uid == uid))
                                {
                                    // Suppose that BuildOverwriteWithSchema do the validation of the overwrite object
                                    var overwriteObject = overwriteApplier.BuildOverwriteWithSchema(od, fm, schemaForCurrentUid);
                                    overwriteApplier.MergeContentWithOverwrite(ref source, overwriteObject, ud.Name, string.Empty, schemaForCurrentUid);

                                    model.LinkToUids      = model.LinkToUids.Union(od.LinkToUids);
                                    model.LinkToFiles     = model.LinkToFiles.Union(od.LinkToFiles);
                                    model.FileLinkSources = model.FileLinkSources.Merge(od.FileLinkSources);
                                    model.UidLinkSources  = model.UidLinkSources.Merge(od.UidLinkSources);
                                }
                            }
                        }
                    }

                    // 1. Validate schema after the merge
                    // TODO: Issue exists - however unable to identify which overwrite document the issue is from
                    ((SchemaDrivenDocumentProcessor)host.Processor).SchemaValidator.Validate(model.Content);

                    // 2. Re-export xrefspec after the merge
                    overwriteApplier.UpdateXrefSpec(model, schema);
                }
                catch (DocumentException e)
                {
                    // Log error here to preserve file info
                    Logger.LogError(e.Message);
                    throw;
                }
            }
        }
Ejemplo n.º 4
0
        public override void Postbuild(ImmutableList<FileModel> models, IHostService host)
        {
            foreach (var uid in host.GetAllUids())
            {
                var ms = host.LookupByUid(uid);
                var ods = ms.Where(m => m.Type == DocumentType.Overwrite).ToList();
                var articles = ms.Except(ods).ToList();
                if (articles.Count == 0 || ods.Count == 0)
                {
                    continue;
                }

                if (articles.Count > 1)
                {
                    throw new DocumentException($"{uid} is defined in multiple articles {articles.Select(s => s.LocalPathFromRoot).ToDelimitedString()}");
                }

                var model = articles[0];
                var schema = model.Properties.Schema as DocumentSchema;
                using (new LoggerFileScope(model.LocalPathFromRoot))
                {
                    var uidDefiniton = model.Uids.Where(s => s.Name == uid).ToList();
                    if (uidDefiniton.Count == 0)
                    {
                        throw new DocfxException($"Unable to find UidDefinition for Uid {uid}");
                    }

                    foreach (var ud in uidDefiniton)
                    {
                        var jsonPointer = new JsonPointer(ud.Path).GetParentPointer();
                        var schemaForCurrentUid = jsonPointer.FindSchema(schema);
                        var source = jsonPointer.GetValue(model.Content);

                        foreach (var od in ods)
                        {
                            using (new LoggerFileScope(od.LocalPathFromRoot))
                            {
                                foreach (var fm in ((IEnumerable<OverwriteDocumentModel>)od.Content).Where(s => s.Uid == uid))
                                {
                                    // Suppose that BuildOverwriteWithSchema do the validation of the overwrite object
                                    var overwriteObject = BuildOverwriteWithSchema(od, fm, host, schemaForCurrentUid);
                                    _merger.Merge(ref source, overwriteObject, ud.Name, string.Empty, schemaForCurrentUid);

                                    model.LinkToUids = model.LinkToUids.Union(od.LinkToUids);
                                    model.LinkToFiles = model.LinkToFiles.Union(od.LinkToFiles);
                                    model.FileLinkSources = model.FileLinkSources.Merge(od.FileLinkSources);
                                    model.UidLinkSources = model.UidLinkSources.Merge(od.UidLinkSources);
                                }
                            }
                        }
                    }

                    // 1. Validate schema after the merge
                    ((SchemaDrivenDocumentProcessor)host.Processor).SchemaValidator.Validate(model.Content);

                    // 2. Re-export xrefspec after the merge
                    var context = new ProcessContext(host, model);
                    _xrefSpecUpdater.Process(model.Content, schema, context);

                    UpdateXRefSpecs((List<XRefSpec>)model.Properties.XRefSpecs, context.XRefSpecs);
                    UpdateXRefSpecs((List<XRefSpec>)model.Properties.ExternalXRefSpecs, context.ExternalXRefSpecs);
                }
            }
        }