Exemplo n.º 1
0
        /// <summary>
        /// Process this instance.
        /// </summary>
        /// <returns>The result.</returns>
        public async Task <IDocumentResult> ProcessAsync()
        {
            var markdownResult = new MarkdownResult(DocumentIdentifier);

            var tr = new StringReader(_content);

            int?   frontMatterStart = null;
            int?   frontMatterEnd   = null;
            string line;
            var    counter = -1;

            var meta = new StringBuilder();
            var body = new StringBuilder();

            while ((line = await tr.ReadLineAsync().ConfigureAwait(false)) != null)
            {
                counter++;

                if (line.Equals("---", StringComparison.OrdinalIgnoreCase))
                {
                    if (!frontMatterStart.HasValue)
                    {
                        frontMatterStart = counter;
                        continue;
                    }

                    if (!frontMatterEnd.HasValue)
                    {
                        frontMatterEnd = counter;
                        continue;
                    }
                }

                // push to meta
                if (frontMatterStart.HasValue &&
                    !frontMatterEnd.HasValue)
                {
                    meta.AppendLine(line);
                }

                // push to body
                else if (frontMatterStart.HasValue &&
                         frontMatterEnd.HasValue)
                {
                    body.AppendLine(line);
                }
            }

            // check structure
            if (frontMatterStart.HasValue &&
                !frontMatterEnd.HasValue)
            {
                throw new KotoriDocumentException(DocumentIdentifier.DocumentId, "Invalid front matter. There is a starting tag --- that is not closed.");
            }

            // no front matter
            if (!frontMatterStart.HasValue &&
                !frontMatterEnd.HasValue)
            {
                body = new StringBuilder(_content);
            }

            markdownResult.FrontMatterType = meta.ToString().ToFrontMatterType();
            markdownResult.Content         = body.ToString();

            IDeserializer des = null;

            if (markdownResult.FrontMatterType == Enums.FrontMatterType.Yaml)
            {
                des = new Yaml();
            }

            if (markdownResult.FrontMatterType == Enums.FrontMatterType.Json)
            {
                des = new Json();
            }

            if (des != null)
            {
                try
                {
                    markdownResult.Meta = des.Deserialize(meta.ToString());
                }
                catch
                {
                    throw new KotoriDocumentException(DocumentIdentifier.DocumentId, "Document parsing error.");
                }
            }

            markdownResult.Date  = _date;
            markdownResult.Draft = _draft ?? false;

            ProcessMeta(markdownResult, DocumentIdentifier.DocumentType);

            if (DocumentIdentifier.DocumentType == Enums.DocumentType.Data)
            {
                markdownResult.Date = DateTime.MinValue.Date;
                markdownResult.Slug = null;
            }

            if (DocumentIdentifier.DocumentType == Enums.DocumentType.Content &&
                markdownResult.Date == null)
            {
                markdownResult.Date = DateTime.MinValue;
            }

            markdownResult.Hash = markdownResult.ToHash();

            return(markdownResult);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Processes the meta.
        /// </summary>
        /// <param name="result">Result.</param>
        void ProcessMeta(MarkdownResult result, Enums.DocumentType documentType)
        {
            var expando         = new ExpandoObject();
            var originalExpando = new ExpandoObject();

            IDictionary <string, object> dictionary         = expando;
            IDictionary <string, object> originalDictionary = originalExpando;

            JObject metaObj = null;

            if (result.Meta != null)
            {
                metaObj = JObject.FromObject(result.Meta);
            }

            Dictionary <string, object> meta = metaObj?.ToObject <Dictionary <string, object> >();
            var usedPropertyTypes            = new List <Enums.DocumentPropertyType>();

            if (meta != null)
            {
                foreach (var key in meta.Keys)
                {
                    var dpt = key.ToDocumentPropertyType();

                    if (dpt == Enums.DocumentPropertyType.Invalid)
                    {
                        throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Document parsing error. Property {key} is not recognized.");
                    }

                    if (dpt == Enums.DocumentPropertyType.Date)
                    {
                        if (documentType == Enums.DocumentType.Data)
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"$Date is not allowed for data documents.");
                        }

                        if (usedPropertyTypes.Any(x => x == Enums.DocumentPropertyType.Date))
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Document parsing error. Property {key} is used more than once.");
                        }

                        if (meta[key].GetType() != typeof(string) &&
                            meta[key].GetType() != typeof(DateTime))
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"$Date is not valid string/date.");
                        }

                        result.Date = meta[key].ToString().ToDateTime();

                        usedPropertyTypes.Add(Enums.DocumentPropertyType.Date);
                    }

                    if (dpt == Enums.DocumentPropertyType.Slug)
                    {
                        if (documentType == Enums.DocumentType.Data)
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"$Slug is not allowed for data documents.");
                        }

                        if (usedPropertyTypes.Any(x => x == Enums.DocumentPropertyType.Slug))
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Document parsing error. Property {key} is used more than once.");
                        }

                        if (meta[key].GetType() != typeof(string))
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"$Slug is not valid string.");
                        }

                        if (!meta[key].ToString().IsValidSlug())
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"$Slug is not valid.");
                        }

                        result.Slug = meta[key].ToString();

                        usedPropertyTypes.Add(Enums.DocumentPropertyType.Slug);
                    }

                    if (dpt == Enums.DocumentPropertyType.Draft)
                    {
                        if (documentType == Enums.DocumentType.Data)
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"$Draft is not allowed for data documents.");
                        }

                        if (usedPropertyTypes.Any(x => x == Enums.DocumentPropertyType.Draft))
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Document parsing error. Property {key} is used more than once.");
                        }

                        if (meta[key].GetType() != typeof(bool))
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"$Draft is not valid boolean.");
                        }

                        result.Draft = (bool)meta[key];

                        usedPropertyTypes.Add(Enums.DocumentPropertyType.Draft);
                    }

                    if (dpt == Enums.DocumentPropertyType.UserDefined)
                    {
                        var newKey = key.ToCamelCase();

                        if (!dictionary.ContainsKey(newKey))
                        {
                            dictionary.Add(newKey, meta[key]);
                        }
                        else
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Document parsing error. Property {key} is used more than once.");
                        }
                    }
                }

                // set original meta
                foreach (var key in dictionary.Keys)
                {
                    originalDictionary.Add(key, dictionary[key]);
                }

                if (_transformation != null)
                {
                    foreach (var t in _transformation.Transformations)
                    {
                        var from    = t.From.ToCamelCase();
                        var to      = t.To.ToCamelCase();
                        var dtpFrom = t.From.ToDocumentPropertyType();
                        var dtpTo   = t.From.ToDocumentPropertyType();

                        if (dtpFrom == Enums.DocumentPropertyType.Invalid)
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Transformation error. Property {t.From} is not valid for transformation (from).");
                        }

                        if (dtpTo == Enums.DocumentPropertyType.Invalid)
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Transformation error. Property {t.From} is not valid for transformation (to).");
                        }

                        if (dtpTo != Enums.DocumentPropertyType.UserDefined)
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Transformation error. Property {t.From} is not valid for transformation (to). Don't use system fields.");
                        }

                        if (!dictionary.ContainsKey(from))
                        {
                            throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Transformation error. Property {t.From} is not valid for transformation (to). Source doesn't exist in meta fields.");
                        }

                        var val = dictionary[from];

                        foreach (var p in t.Transformations)
                        {
                            var newVal = _transformation.Transform(from, val, p);

                            if (dictionary.ContainsKey(to))
                            {
                                dictionary[to] = newVal;
                            }
                            else
                            {
                                dictionary.Add(to, newVal);
                            }

                            val = newVal;
                        }
                    }
                }
            }

            // no date, set min date
            if (!result.Date.HasValue)
            {
                result.Date = DateTime.MinValue.Date;
            }

            // no slug, set from document identifier
            if (documentType == Enums.DocumentType.Content &&
                result.Slug == null)
            {
                if (!DocumentIdentifier.DocumentId.IsValidSlug())
                {
                    throw new KotoriDocumentException(DocumentIdentifier.DocumentId, $"Document identifier {DocumentIdentifier.DocumentId} is not valid as a slug.");
                }

                result.Slug = DocumentIdentifier.DocumentId;
            }

            result.OriginalMeta = originalExpando;
            result.Meta         = expando;
        }