Пример #1
0
 public ManifestItemWithContext(InternalManifestItem item, FileModel model, IDocumentProcessor processor, TemplateBundle bundle)
 {
     Item           = item;
     FileModel      = model;
     Processor      = processor;
     TemplateBundle = bundle;
 }
Пример #2
0
        public SystemMetadata Generate(InternalManifestItem item)
        {
            var attrs = new SystemMetadata
            {
                Language = Constants.DefaultLanguage,
            };

            string key = GetFileKey(item.Key);

            attrs.Key = ((RelativePath)key).RemoveWorkingFolder();
            var file = (RelativePath)(item.FileWithoutExtension + item.Extension);

            attrs.RelativePathToRoot = (RelativePath.Empty).MakeRelativeTo(file);
            var fileWithoutWorkingFolder = file.RemoveWorkingFolder();

            attrs.Path = fileWithoutWorkingFolder;

            if (!string.IsNullOrEmpty(_context.VersionName))
            {
                attrs.VersionName   = _context.VersionName;
                attrs.VersionFolder = _context.VersionFolder;
            }

            // 1. Root Toc is specified by RootTocKey, or by default in the top directory of output folder
            if (!string.IsNullOrEmpty(_context.RootTocPath))
            {
                attrs.RootTocKey = _context.RootTocPath;
                var rootTocPath = ((RelativePath)_context.RootTocPath).RemoveWorkingFolder();
                attrs.RootTocPath           = rootTocPath;
                attrs.RelativePathToRootToc = rootTocPath.MakeRelativeTo(file);
            }
            else
            {
                GetRootTocFromOutputRoot(attrs, file);
            }

            // 2. The algorithm of toc current article belongs to:
            //    a. If toc can be found in TocMap, return that toc
            //    b. Elsewise, get the nearest toc, **nearest** means nearest toc in **OUTPUT** folder
            var parentTocFiles = _context.GetTocFileKeySet(key)?.Select(s => new FileInfo(s, (RelativePath)_context.GetFilePath(s)));
            var parentToc      = GetNearestToc(parentTocFiles, file) ?? GetDefaultToc(key);

            if (parentToc != null)
            {
                var parentTocPath = parentToc.File.RemoveWorkingFolder();
                attrs.TocPath = parentTocPath;
                var tocRelativePath = parentTocPath.MakeRelativeTo(file);
                attrs.RelativePathToToc = tocRelativePath;
                attrs.TocKey            = parentToc.Key;
                Logger.LogDiagnostic($"TOC file {parentTocPath} is found for {item.LocalPathFromRoot}.");
            }
            else
            {
                Logger.LogDiagnostic($"TOC file for {item.LocalPathFromRoot} is not found.");
            }

            return(attrs);
        }
Пример #3
0
        public SystemMetadata Generate(InternalManifestItem item)
        {
            var attrs = new SystemMetadata
            {
                Language = Constants.DefaultLanguage,
            };

            string key  = GetFileKey(item.Key);
            var    file = (TypeForwardedToRelativePath)(item.FileWithoutExtension + item.Extension);

            attrs.RelativePathToRoot = (TypeForwardedToRelativePath.Empty).MakeRelativeTo(file);
            var fileWithoutWorkingFolder = file.RemoveWorkingFolder();

            attrs.Path = fileWithoutWorkingFolder;

            // 1. Root Toc is always in the top directory of output folder
            var rootToc = _toc.FirstOrDefault();

            if (rootToc != null)
            {
                var rootTocPath = rootToc.File.RemoveWorkingFolder();
                if (rootTocPath.SubdirectoryCount == 0)
                {
                    attrs.RootTocPath = rootTocPath;
                    var rootTocRelativePath = rootTocPath.MakeRelativeTo(file);
                    attrs.RelativePathToRootToc = rootTocRelativePath;
                    attrs.RootTocKey            = rootToc.Key;
                    Logger.LogVerbose($"Root TOC file {rootTocPath} is found.");
                }
                else
                {
                    Logger.LogVerbose($"Root TOC file from output folder is not found, the toppest TOC file is {rootTocPath}");
                }
            }

            // 2. The algorithm of toc current article belongs to:
            //    a. If toc can be found in TocMap, return that toc
            //    b. Elsewise, get the nearest toc, **nearest** means nearest toc in **OUTPUT** folder
            var parentTocFiles = _context.GetTocFileKeySet(key)?.Select(s => new FileInfo(s, (TypeForwardedToRelativePath)_context.GetFilePath(s)));
            var parentToc      = GetNearestToc(parentTocFiles, file) ?? GetDefaultToc(key);

            if (parentToc != null)
            {
                var parentTocPath = parentToc.File.RemoveWorkingFolder();
                attrs.TocPath = parentTocPath;
                var tocRelativePath = parentTocPath.MakeRelativeTo(file);
                attrs.RelativePathToToc = tocRelativePath;
                attrs.TocKey            = parentToc.Key;
                Logger.LogVerbose($"TOC file {parentTocPath} is found for {item.LocalPathFromRoot}.");
            }
            else
            {
                Logger.LogVerbose($"TOC file for {item.LocalPathFromRoot} is not found.");
            }

            return(attrs);
        }
Пример #4
0
        private IEnumerable <TransformModelOptions> GetOptionsForEachTemplate(InternalManifestItem item, IDocumentBuildContext context)
        {
            if (item == null)
            {
                yield break;
            }

            foreach (var template in Templates)
            {
                if (template.ContainsGetOptions)
                {
                    yield return(template.GetOptions(item.Model.Content));
                }
            }
        }
        /// <summary>
        /// Must guarantee thread safety
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        internal ManifestItem Transform(InternalManifestItem item)
        {
            if (item.Model == null || item.Model.Content == null)
            {
                throw new ArgumentNullException("Content for item.Model should not be null!");
            }
            var model = ConvertObjectToDictionary(item.Model.Content);

            model = AppendGlobalMetadata(model);
            if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportRawModel))
            {
                ExportModel(model, item.FileWithoutExtension, _settings.RawModelExportSettings);
            }

            var manifestItem = new ManifestItem
            {
                DocumentType       = item.DocumentType,
                SourceRelativePath = item.LocalPathFromRoot,
                Metadata           = item.Metadata,
                Version            = _context.VersionName,
            };
            var outputDirectory = _settings.OutputFolder ?? Directory.GetCurrentDirectory();

            // 1. process resource
            if (item.ResourceFile != null)
            {
                // Resource file has already been processed in its plugin
                var ofi = new OutputFileInfo
                {
                    RelativePath = item.ResourceFile,
                    LinkToPath   = GetLinkToPath(item.ResourceFile),
                };
                manifestItem.OutputFiles.Add("resource", ofi);
            }

            // 2. process model
            var templateBundle = _templateCollection[item.DocumentType];

            if (templateBundle == null)
            {
                return(manifestItem);
            }

            HashSet <string> missingUids = new HashSet <string>();

            // Must convert to JObject first as we leverage JsonProperty as the property name for the model
            foreach (var template in templateBundle.Templates)
            {
                if (!template.ContainsTemplateRenderer)
                {
                    continue;
                }
                try
                {
                    var    extension  = template.Extension;
                    string outputFile = item.FileWithoutExtension + extension;
                    object viewModel  = null;
                    try
                    {
                        viewModel = template.TransformModel(model);
                    }
                    catch (Exception e)
                    {
                        string message;
                        if (_settings.DebugMode)
                        {
                            // save raw model for further investigation:
                            var rawModelPath = ExportModel(model, item.FileWithoutExtension, _settings.RawModelExportSettingsForDebug);
                            message = $"Error transforming model \"{rawModelPath}\" generated from \"{item.LocalPathFromRoot}\" using \"{template.ScriptName}\". {e.Message}";
                        }
                        else
                        {
                            message = $"Error transforming model generated from \"{item.LocalPathFromRoot}\" using \"{template.ScriptName}\". To get the detailed raw model, please run docfx with debug mode --debug. {e.Message} ";
                        }

                        Logger.LogError(message);
                        throw new DocumentException(message, e);
                    }

                    string result;
                    try
                    {
                        result = template.Transform(viewModel);
                    }
                    catch (Exception e)
                    {
                        string message;
                        if (_settings.DebugMode)
                        {
                            // save view model for further investigation:
                            var viewModelPath = ExportModel(viewModel, outputFile, _settings.ViewModelExportSettingsForDebug);
                            message = $"Error applying template \"{template.Name}\" to view model \"{viewModelPath}\" generated from \"{item.LocalPathFromRoot}\". {e.Message}";
                        }
                        else
                        {
                            message = $"Error applying template \"{template.Name}\" generated from \"{item.LocalPathFromRoot}\". To get the detailed view model, please run docfx with debug mode --debug. {e.Message}";
                        }

                        Logger.LogError(message);
                        throw new DocumentException(message, e);
                    }

                    if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportViewModel))
                    {
                        ExportModel(viewModel, outputFile, _settings.ViewModelExportSettings);
                    }

                    if (_settings.Options.HasFlag(ApplyTemplateOptions.TransformDocument))
                    {
                        if (string.IsNullOrWhiteSpace(result))
                        {
                            string message;
                            if (_settings.DebugMode)
                            {
                                var viewModelPath = ExportModel(viewModel, outputFile, _settings.ViewModelExportSettingsForDebug);
                                message = $"Model \"{viewModelPath}\" is transformed to empty string with template \"{template.Name}\"";
                            }
                            else
                            {
                                message = $"Model is transformed to empty string with template \"{template.Name}\". To get the detailed view model, please run docfx with debug mode --debug";
                            }
                            Logger.LogWarning(message);
                        }

                        TransformDocument(result ?? string.Empty, extension, _context, outputFile, missingUids, manifestItem);
                        Logger.LogDiagnostic($"Transformed model \"{item.LocalPathFromRoot}\" to \"{outputFile}\".");
                    }
                }
                catch (PathTooLongException e)
                {
                    var message = $"Error processing {item.LocalPathFromRoot}: {e.Message}";
                    throw new PathTooLongException(message, e);
                }
            }

            if (missingUids.Count > 0)
            {
                var uids = string.Join(", ", missingUids.Select(s => $"\"{s}\""));
                Logger.LogWarning($"Invalid cross reference {uids}.", null, item.LocalPathFromRoot);
            }

            return(manifestItem);
        }
Пример #6
0
        /// <summary>
        /// Must guarantee thread safety
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        internal ManifestItem Transform(InternalManifestItem item)
        {
            if (item.Model == null || item.Model.Content == null)
            {
                throw new ArgumentNullException("Content for item.Model should not be null!");
            }
            var model = ConvertObjectToDictionary(item.Model.Content);

            model = AppendGlobalMetadata(model);
            if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportRawModel))
            {
                ExportModel(model, item.FileWithoutExtension, _settings.RawModelExportSettings);
            }

            var manifestItem = new ManifestItem
            {
                DocumentType       = item.DocumentType,
                SourceRelativePath = item.LocalPathFromRoot,
                OutputFiles        = new Dictionary <string, OutputFileInfo>(),
                Metadata           = item.Metadata,
            };
            var outputDirectory = _settings.OutputFolder ?? Environment.CurrentDirectory;

            // 1. process resource
            if (item.ResourceFile != null)
            {
                // Resource file has already been processed in its plugin
                manifestItem.OutputFiles.Add("resource", new OutputFileInfo
                {
                    RelativePath = item.ResourceFile,
                    LinkToPath   = null,
                    Hash         = null
                });
            }

            // 2. process model
            var templateBundle = _templateCollection[item.DocumentType];

            if (templateBundle == null)
            {
                return(manifestItem);
            }

            HashSet <string> missingUids = new HashSet <string>();

            // Must convert to JObject first as we leverage JsonProperty as the property name for the model
            foreach (var template in templateBundle.Templates)
            {
                if (!template.ContainsTemplateRenderer)
                {
                    continue;
                }

                var    extension  = template.Extension;
                string outputFile = item.FileWithoutExtension + extension;
                string outputPath = Path.Combine(outputDirectory, outputFile);
                var    dir        = Path.GetDirectoryName(outputPath);
                if (!string.IsNullOrEmpty(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                object viewModel = null;
                try
                {
                    viewModel = template.TransformModel(model);
                }
                catch (Exception e)
                {
                    // save raw model for further investigation:
                    var exportSettings = ApplyTemplateSettings.RawModelExportSettingsForDebug;
                    var rawModelPath   = ExportModel(model, item.FileWithoutExtension, exportSettings);
                    var message        = $"Error transforming model \"{rawModelPath}\" generated from \"{item.LocalPathFromRoot}\" using \"{template.ScriptName}\": {e.Message}";
                    Logger.LogError(message);
                    throw new DocumentException(message, e);
                }

                string result;
                try
                {
                    result = template.Transform(viewModel);
                }
                catch (Exception e)
                {
                    // save view model for further investigation:
                    var exportSettings = ApplyTemplateSettings.ViewModelExportSettingsForDebug;
                    var viewModelPath  = ExportModel(viewModel, outputFile, exportSettings);
                    var message        = $"Error applying template \"{template.Name}\" to view model \"{viewModelPath}\" generated from \"{item.LocalPathFromRoot}\": {e.Message}";
                    Logger.LogError(message);
                    throw new DocumentException(message, e);
                }

                if (_settings.Options.HasFlag(ApplyTemplateOptions.ExportViewModel))
                {
                    ExportModel(viewModel, outputFile, _settings.ViewModelExportSettings);
                }

                if (_settings.Options.HasFlag(ApplyTemplateOptions.TransformDocument))
                {
                    if (string.IsNullOrWhiteSpace(result))
                    {
                        // TODO: WHAT to do if is transformed to empty string? STILL creat empty file?
                        var exportSettings = ApplyTemplateSettings.ViewModelExportSettingsForDebug;
                        var viewModelPath  = ExportModel(viewModel, outputFile, exportSettings);
                        Logger.LogWarning($"Model \"{viewModelPath}\" is transformed to empty string with template \"{template.Name}\"");
                        File.WriteAllText(outputPath, string.Empty);
                    }
                    else
                    {
                        TransformDocument(result, extension, _context, outputPath, outputFile, missingUids, manifestItem);
                        Logger.LogDiagnostic($"Transformed model \"{item.LocalPathFromRoot}\" to \"{outputPath}\".");
                    }
                }
            }

            if (missingUids.Count > 0)
            {
                var uids = string.Join(", ", missingUids.Select(s => $"\"{s}\""));
                Logger.LogWarning($"Unable to resolve cross-reference {uids}");
            }

            return(manifestItem);
        }
Пример #7
0
 internal TransformModelOptions GetOptions(InternalManifestItem item, IDocumentBuildContext context)
 {
     return(MergeOptions(GetOptionsForEachTemplate(item, context)));
 }