Example #1
0
        // TODO: remove
        public void Process(DocumentBuildContext context, string outputDirectory)
        {
            var baseDirectory = context.BuildOutputFolder;

            if (string.IsNullOrEmpty(outputDirectory)) outputDirectory = Environment.CurrentDirectory;
            if (string.IsNullOrEmpty(baseDirectory)) baseDirectory = Environment.CurrentDirectory;

            if (!Directory.Exists(outputDirectory)) Directory.CreateDirectory(outputDirectory);

            // 1. Copy dependent files with path relative to the base output directory
            ProcessDependencies(outputDirectory);
            UpdateFileMap(context, outputDirectory, Templates);
            List<TemplateManifestItem> manifest = new List<TemplateManifestItem>();

            // 3. Process every model and save to output directory
            foreach (var item in context.Manifest)
            {
                var manifestItem = Transform(context, item, Templates, outputDirectory, true, s => s + ".json");
                manifest.Add(manifestItem);
            }

            // Save manifest
            var manifestPath = Path.Combine(outputDirectory, ManifestFileName);
            JsonUtility.Serialize(manifestPath, manifest);
            Logger.Log(LogLevel.Verbose, $"Manifest file saved to {manifestPath}.");
        }
Example #2
0
 private void BuildCore(
     IDocumentProcessor processor,
     IEnumerable <FileAndType> files,
     ImmutableDictionary <string, object> metadata,
     FileMetadata fileMetadata,
     DocumentBuildContext context)
 {
     Logger.LogInfo($"Plug-in {processor.Name}: Loading document...");
     using (var hostService = new HostService(
                from file in files
                select Load(processor, metadata, fileMetadata, file)))
     {
         hostService.SourceFiles = context.AllSourceFiles;
         foreach (var m in hostService.Models)
         {
             if (m.LocalPathFromRepoRoot == null)
             {
                 m.LocalPathFromRepoRoot = Path.Combine(m.BaseDir, m.File);
             }
         }
         Logger.LogInfo($"Plug-in {processor.Name}: Document loaded (count = {hostService.Models.Count}).");
         Logger.LogInfo($"Plug-in {processor.Name}: Preprocessing...");
         Prebuild(processor, hostService);
         Logger.LogInfo($"Plug-in {processor.Name}: Building...");
         BuildArticle(processor, hostService);
         Logger.LogInfo($"Plug-in {processor.Name}: Postprocessing...");
         Postbuild(processor, hostService);
         Logger.LogInfo($"Plug-in {processor.Name}: Saving...");
         Save(processor, hostService, context);
     }
 }
Example #3
0
 private void Save(IDocumentProcessor processor, HostService hostService, DocumentBuildContext context)
 {
     hostService.Models.RunAll(
         m =>
     {
         try
         {
             if (m.Type != DocumentType.Override)
             {
                 using (new LoggerFileScope(m.OriginalFileAndType.File))
                 {
                     Logger.LogVerbose($"Plug-in {processor.Name}: Saving...");
                     m.BaseDir  = context.BuildOutputFolder;
                     var result = processor.Save(m);
                     if (result != null)
                     {
                         HandleSaveResult(context, hostService, m, result);
                     }
                 }
             }
         }
         finally
         {
             m.Dispose();
         }
     });
 }
Example #4
0
        private void Transform(DocumentBuildContext context, TemplateCollection templateCollection, bool exportMetadata)
        {
            if (templateCollection == null || templateCollection.Count == 0)
            {
                Logger.LogWarning("No template is found.");
            }
            else
            {
                Logger.LogInfo("Start applying template...");
            }

            var outputDirectory = context.BuildOutputFolder;

            List <TemplateManifestItem> manifest = new List <TemplateManifestItem>();

            // Model can apply multiple template with different extension, so append the view model extension instead of change extension
            Func <string, string> metadataPathProvider = (s) => { return(s + ViewModelExtension); };

            foreach (var item in context.Manifest)
            {
                var manifestItem = TemplateProcessor.Transform(context, item, templateCollection, outputDirectory, exportMetadata, metadataPathProvider);
                manifest.Add(manifestItem);
            }

            // Save manifest
            var manifestPath = Path.Combine(outputDirectory, ManifestFileName);

            JsonUtility.Serialize(manifestPath, manifest);
            Logger.Log(LogLevel.Verbose, $"Manifest file saved to {manifestPath}.");
        }
Example #5
0
 private void Save(IDocumentProcessor processor, HostService hostService, DocumentBuildContext context)
 {
     hostService.Models.RunAll(
         m =>
     {
         if (m.Type != DocumentType.Override)
         {
             using (new LoggerFileScope(m.OriginalFileAndType.File))
             {
                 Logger.LogVerbose($"Plug-in {processor.Name}: Saving...");
                 m.BaseDir = context.BuildOutputFolder;
                 if (m.PathRewriter != null)
                 {
                     m.File = m.PathRewriter(m.File);
                 }
                 var result = processor.Save(m);
                 if (result != null)
                 {
                     m.File           = TemplateProcessor.UpdateFilePath(m.File, result.DocumentType, context.TemplateCollection);
                     result.ModelFile = TemplateProcessor.UpdateFilePath(result.ModelFile, result.DocumentType, context.TemplateCollection);
                     HandleSaveResult(context, hostService, m, result);
                 }
             }
         }
     });
 }
Example #6
0
 private static void HandleUids(DocumentBuildContext context, SaveResult result)
 {
     if (result.LinkToUids.Count > 0)
     {
         context.XRef.UnionWith(result.LinkToUids.Where(s => s != null));
     }
 }
Example #7
0
        private void GetTocInfo(DocumentBuildContext context, ManifestItem item)
        {
            string relativePath = item.OriginalFile;
            var tocMap = context.TocMap;
            var fileMap = context.FileMap;
            HashSet<string> parentTocs;
            string parentToc = null;
            string rootToc = null;
            string currentPath = ((RelativePath)relativePath).GetPathFromWorkingFolder();
            while (tocMap.TryGetValue(currentPath, out parentTocs) && parentTocs.Count > 0)
            {
                // Get the first toc only
                currentPath = parentTocs.First();
                rootToc = currentPath;
                if (parentToc == null) parentToc = currentPath;
                currentPath = ((RelativePath)currentPath).GetPathFromWorkingFolder();
            }
            if (rootToc != null)
            {
                rootToc = fileMap[((RelativePath)rootToc).GetPathFromWorkingFolder()];
                PathUtility.TryGetPathFromWorkingFolder(rootToc, out rootToc);
                RootTocPath = rootToc;
            }

            if (parentToc == null) TocPath = RootTocPath;
            else
            {
                parentToc = fileMap[((RelativePath)parentToc).GetPathFromWorkingFolder()];
                PathUtility.TryGetPathFromWorkingFolder(parentToc, out parentToc);
                TocPath = parentToc;
            }
        }
Example #8
0
 public SystemAttributes(DocumentBuildContext context, ManifestItem item, string lang)
 {
     Language = lang;
     GetTocInfo(context, item);
     TocRelativePath = TocPath == null ? null : ((RelativePath)TocPath).MakeRelativeTo((RelativePath)item.ModelFile);
     RootTocRelativePath = RootTocPath == null ? null : ((RelativePath)RootTocPath).MakeRelativeTo((RelativePath)item.ModelFile);
     RelativePathToRoot = (RelativePath.Empty).MakeRelativeTo((RelativePath)item.ModelFile);
 }
Example #9
0
        public void Build(DocumentBuildParameters parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }
            if (parameters.OutputBaseDir == null)
            {
                throw new ArgumentException("Output folder cannot be null.", nameof(parameters) + "." + nameof(parameters.OutputBaseDir));
            }
            if (parameters.Files == null)
            {
                throw new ArgumentException("Source files cannot be null.", nameof(parameters) + "." + nameof(parameters.Files));
            }
            if (parameters.Metadata == null)
            {
                parameters.Metadata = ImmutableDictionary<string, object>.Empty;
            }

            using (new LoggerPhaseScope(Phase))
            {
                Directory.CreateDirectory(parameters.OutputBaseDir);
                var context = new DocumentBuildContext(
                    Path.Combine(Environment.CurrentDirectory, parameters.OutputBaseDir),
                    parameters.Files.EnumerateFiles(),
                    parameters.ExternalReferencePackages);
                Logger.LogInfo("Start building document ...");
                foreach (var item in
                    from file in parameters.Files.EnumerateFiles()
                    group file by (from processor in Processors
                                   let priority = processor.GetProcessingPriority(file)
                                   where priority != ProcessingPriority.NotSupportted
                                   orderby priority descending
                                   select processor).FirstOrDefault())
                {
                    if (item.Key != null)
                    {
                        BuildCore(item.Key, item, parameters.Metadata, parameters.FileMetadata, context);
                    }
                    else
                    {
                        var sb = new StringBuilder();
                        sb.AppendLine("Cannot handle following file:");
                        foreach (var f in item)
                        {
                            sb.Append("\t");
                            sb.AppendLine(f.File);
                        }
                        Logger.LogWarning(sb.ToString());
                    }
                }

                context.SerializeTo(parameters.OutputBaseDir);
                Logger.LogInfo("Building document completed.");
            }
        }
Example #10
0
        public void Build(DocumentBuildParameters parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }
            if (parameters.OutputBaseDir == null)
            {
                throw new ArgumentException("Output folder cannot be null.", nameof(parameters) + "." + nameof(parameters.OutputBaseDir));
            }
            if (parameters.Files == null)
            {
                throw new ArgumentException("Source files cannot be null.", nameof(parameters) + "." + nameof(parameters.Files));
            }
            if (parameters.Metadata == null)
            {
                parameters.Metadata = ImmutableDictionary <string, object> .Empty;
            }

            using (new LoggerPhaseScope(Phase))
            {
                Directory.CreateDirectory(parameters.OutputBaseDir);
                var context = new DocumentBuildContext(
                    Path.Combine(Environment.CurrentDirectory, parameters.OutputBaseDir),
                    parameters.Files.EnumerateFiles(),
                    parameters.ExternalReferencePackages);
                Logger.LogInfo("Start building document ...");
                foreach (var item in
                         from file in parameters.Files.EnumerateFiles()
                         group file by(from processor in Processors
                                       let priority = processor.GetProcessingPriority(file)
                                                      where priority != ProcessingPriority.NotSupportted
                                                      orderby priority descending
                                                      select processor).FirstOrDefault())
                {
                    if (item.Key != null)
                    {
                        BuildCore(item.Key, item, parameters.Metadata, parameters.FileMetadata, context);
                    }
                    else
                    {
                        var sb = new StringBuilder();
                        sb.AppendLine("Cannot handle following file:");
                        foreach (var f in item)
                        {
                            sb.Append("\t");
                            sb.AppendLine(f.File);
                        }
                        Logger.LogWarning(sb.ToString());
                    }
                }

                context.SerializeTo(parameters.OutputBaseDir);
                Logger.LogInfo("Building document completed.");
            }
        }
Example #11
0
 public static DocumentBuildContext DeserializeFrom(string outputBaseDir)
 {
     var context = new DocumentBuildContext(outputBaseDir);
     context.Manifest = YamlUtility.Deserialize<List<ManifestItem>>(Path.Combine(outputBaseDir, ManifestFileName));
     context.FileMap = new Dictionary<string, string>(YamlUtility.Deserialize<Dictionary<string, string>>(Path.Combine(outputBaseDir, FileMapFileName)), FilePathComparer.OSPlatformSensitiveStringComparer);
     context.ExternalXRefSpec = YamlUtility.Deserialize<List<XRefSpec>>(Path.Combine(outputBaseDir, ExternalXRefSpecFileName)).ToDictionary(x => x.Uid, x => x.ToReadOnly());
     context.XRefSpecMap = YamlUtility.Deserialize<List<XRefSpec>>(Path.Combine(outputBaseDir, InternalXRefSpecFileName)).ToDictionary(x => x.Uid, x => x.ToReadOnly());
     context.TocMap = new Dictionary<string, HashSet<string>>(YamlUtility.Deserialize<Dictionary<string, HashSet<string>>>(Path.Combine(outputBaseDir, TocFileName)), FilePathComparer.OSPlatformSensitiveStringComparer);
     return context;
 }
Example #12
0
 private static void HandleUids(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     foreach (var uid in model.Uids)
     {
         context.UidMap[uid] = ((RelativePath)model.File).GetPathFromWorkingFolder();
     }
     if (result.LinkToUids.Length > 0)
     {
         context.XRef.UnionWith(result.LinkToUids);
     }
 }
        public static DocumentBuildContext DeserializeFrom(string outputBaseDir)
        {
            var context = new DocumentBuildContext(outputBaseDir);

            context.Manifest         = YamlUtility.Deserialize <List <ManifestItem> >(Path.Combine(outputBaseDir, ManifestFileName));
            context.FileMap          = new Dictionary <string, string>(YamlUtility.Deserialize <Dictionary <string, string> >(Path.Combine(outputBaseDir, FileMapFileName)), FilePathComparer.OSPlatformSensitiveStringComparer);
            context.ExternalXRefSpec = YamlUtility.Deserialize <List <XRefSpec> >(Path.Combine(outputBaseDir, ExternalXRefSpecFileName)).ToDictionary(x => x.Uid, x => x.ToReadOnly());
            context.XRefSpecMap      = YamlUtility.Deserialize <List <XRefSpec> >(Path.Combine(outputBaseDir, InternalXRefSpecFileName)).ToDictionary(x => x.Uid, x => x.ToReadOnly());
            context.TocMap           = new Dictionary <string, HashSet <string> >(YamlUtility.Deserialize <Dictionary <string, HashSet <string> > >(Path.Combine(outputBaseDir, TocFileName)), FilePathComparer.OSPlatformSensitiveStringComparer);
            return(context);
        }
Example #14
0
 private static void RegisterManifest(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     context.Manifest.Add(new ManifestItem
     {
         DocumentType = result.DocumentType,
         ModelFile    = result.ModelFile,
         ResourceFile = result.ResourceFile,
         OriginalFile = model.OriginalFileAndType.File,
         // TODO: What is API doc's LocalPathToRepo? => defined in ManagedReferenceDocumentProcessor
         LocalPathFromRepoRoot = model.LocalPathFromRepoRoot
     });
 }
Example #15
0
 private static ManifestItem GetManifestItem(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     return(new ManifestItem
     {
         DocumentType = result.DocumentType,
         ModelFile = result.ModelFile,
         ResourceFile = result.ResourceFile,
         Key = model.Key,
         // TODO: What is API doc's LocalPathToRepo? => defined in ManagedReferenceDocumentProcessor
         LocalPathFromRepoRoot = model.LocalPathFromRepoRoot,
         Model = model.ModelWithCache,
         InputFolder = model.OriginalFileAndType.BaseDir
     });
 }
Example #16
0
 private void HandleSaveResult(
     DocumentBuildContext context,
     HostService hostService,
     FileModel model,
     SaveResult result)
 {
     context.FileMap[((RelativePath)model.OriginalFileAndType.File).GetPathFromWorkingFolder()] = ((RelativePath)model.File).GetPathFromWorkingFolder();
     DocumentException.RunAll(
         () => CheckFileLink(hostService, model, result),
         () => HandleUids(context, model, result),
         () => HandleToc(context, result),
         () => RegisterXRefSpec(context, model, result),
         () => RegisterManifest(context, model, result));
 }
Example #17
0
        private ManifestItem HandleSaveResult(
            DocumentBuildContext context,
            HostService hostService,
            FileModel model,
            SaveResult result)
        {
            context.FileMap[model.Key] = ((RelativePath)model.File).GetPathFromWorkingFolder();
            DocumentException.RunAll(
                () => CheckFileLink(hostService, result),
                () => HandleUids(context, result),
                () => HandleToc(context, result),
                () => RegisterXRefSpec(context, result));

            return(GetManifestItem(context, model, result));
        }
Example #18
0
 private void RegisterXRefSpec(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     foreach (var spec in result.XRefSpecs)
     {
         if (!string.IsNullOrWhiteSpace(spec?.Uid))
         {
             if (context.XRefSpecMap.ContainsKey(spec.Uid))
             {
                 Logger.LogWarning($"Uid({spec.Uid}) duplicated.", file: model.LocalPathFromRepoRoot);
             }
             else
             {
                 context.XRefSpecMap[spec.Uid] = spec.ToReadOnly();
             }
         }
     }
 }
Example #19
0
 private void RegisterXRefSpec(DocumentBuildContext context, SaveResult result)
 {
     foreach (var spec in result.XRefSpecs)
     {
         if (!string.IsNullOrWhiteSpace(spec?.Uid))
         {
             XRefSpec xref;
             if (context.XRefSpecMap.TryGetValue(spec.Uid, out xref))
             {
                 Logger.LogWarning($"Uid({spec.Uid}) has already been defined in {((RelativePath)xref.Href).RemoveWorkingFolder()}.");
             }
             else
             {
                 context.XRefSpecMap[spec.Uid] = spec.ToReadOnly();
             }
         }
     }
 }
Example #20
0
        private void UpdateContext(DocumentBuildContext context)
        {
            //update internal XrefMap
            if (context.XRefSpecMap != null)
            {
                foreach (var pair in context.XRefSpecMap)
                {
                    string targetFilePath;
                    if (context.FileMap.TryGetValue(pair.Value.Href, out targetFilePath))
                    {
                        pair.Value.Href = targetFilePath;
                    }
                    else
                    {
                        Logger.LogWarning($"{pair.Value.Href} is not found in .filemap");
                    }
                }
            }

            context.SetExternalXRefSpec();
        }
Example #21
0
        public static void UpdateFileMap(DocumentBuildContext context, string outputDirectory, TemplateCollection templateCollection)
        {
            //update internal XrefMap
            if (context.XRefSpecMap != null)
            {
                foreach (var pair in context.XRefSpecMap)
                {
                    string targetFilePath;
                    if (context.FileMap.TryGetValue(pair.Value.Href, out targetFilePath))
                    {
                        pair.Value.Href = targetFilePath;
                    }
                    else
                    {
                        Logger.LogWarning($"{pair.Value.Href} is not found in .filemap");
                    }
                }
            }

            context.SetExternalXRefSpec();
        }
Example #22
0
 private static void HandleToc(DocumentBuildContext context, SaveResult result)
 {
     if (result.TocMap?.Count > 0)
     {
         foreach (var toc in result.TocMap)
         {
             HashSet <string> list;
             if (context.TocMap.TryGetValue(toc.Key, out list))
             {
                 foreach (var item in toc.Value)
                 {
                     list.Add(item);
                 }
             }
             else
             {
                 context.TocMap[toc.Key] = toc.Value;
             }
         }
     }
 }
Example #23
0
 private static void HandleUids(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     foreach (var uid in model.Uids)
     {
         context.UidMap[uid] = ((RelativePath)model.File).GetPathFromWorkingFolder();
     }
     if (result.LinkToUids.Count > 0)
     {
         foreach (var item in result.LinkToUids)
         {
             HashSet <string> files;
             if (context.XRef.TryGetValue(item.Key, out files))
             {
                 files.UnionWith(item.Value);
             }
             else
             {
                 context.XRef[item.Key] = item.Value;
             }
         }
     }
 }
Example #24
0
        private void ProcessTemplate(DocumentBuildContext context, string outputDirectory)
        {
            if (_templates == null || _templates.Count == 0)
            {
                Logger.Log(LogLevel.Info, "Template is not specified, files will not be transformed.");
                return;
            }

            using (var templateResource = new CompositeResourceCollectionWithOverridden(_templates.Select(s => _finder.Find(s)).Where(s => s != null)))
            {
                if (templateResource.IsEmpty)
                {
                    Logger.Log(LogLevel.Warning, $"No template resource found for [{_templates.ToDelimitedString()}].");
                }
                else
                {
                    Logger.Log(LogLevel.Verbose, "Template resource found, starting applying template.");
                    using (var processor = new TemplateProcessor(templateResource))
                    {
                        processor.Process(context, outputDirectory);
                    }
                }
            }
        }
Example #25
0
        private static void TranformHtml(DocumentBuildContext context, string transformed, string relativeModelPath, string outputPath)
        {
            // Update HREF and XREF
            var internalXref = context.XRefSpecMap;
            var externalXref = context.ExternalXRefSpec;
            HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument();
            html.LoadHtml(transformed);

            var xrefExceptions = new List<CrossReferenceNotResolvedException>();
            var xrefNodes = html.DocumentNode.SelectNodes("//xref/@href");
            if (xrefNodes != null)
            {
                foreach(var xref in xrefNodes)
                {
                    try
                    {
                        UpdateXref(xref, internalXref, externalXref, Language);
                    }
                    catch (CrossReferenceNotResolvedException e)
                    {
                        xrefExceptions.Add(e);
                    }
                }
            }

            var srcNodes = html.DocumentNode.SelectNodes("//*/@src");
            if (srcNodes != null)
                foreach (var link in srcNodes)
                {
                    UpdateHref(link, "src", context.FileMap, relativeModelPath);
                }

            var hrefNodes = html.DocumentNode.SelectNodes("//*/@href");
            if (hrefNodes != null)
            {
                foreach (var link in hrefNodes)
                {
                    UpdateHref(link, "href", context.FileMap, relativeModelPath);
                }
            }

            // Save with extension changed
            var subDirectory = Path.GetDirectoryName(outputPath);
            if (!string.IsNullOrEmpty(subDirectory) && !Directory.Exists(subDirectory)) Directory.CreateDirectory(subDirectory);
            html.Save(outputPath, Encoding.UTF8);
            if (xrefExceptions.Count > 0)
            {
                throw new AggregateException(xrefExceptions);
            }
        }
Example #26
0
        private void Transform(DocumentBuildContext context, TemplateCollection templateCollection, bool exportMetadata)
        {
            if (templateCollection == null || templateCollection.Count == 0)
            {
                Logger.LogWarning("No template is found.");
            }
            else
            {
                Logger.LogInfo("Start applying template...");
            }

            var outputDirectory = context.BuildOutputFolder;

            List<TemplateManifestItem> manifest = new List<TemplateManifestItem>();

            // Model can apply multiple template with different extension, so append the view model extension instead of change extension
            Func<string, string> metadataPathProvider = (s) => { return s + ViewModelExtension; };
            foreach (var item in context.Manifest)
            {
                var manifestItem = TemplateProcessor.Transform(context, item, templateCollection, outputDirectory, exportMetadata, metadataPathProvider);
                manifest.Add(manifestItem);
            }

            // Save manifest
            var manifestPath = Path.Combine(outputDirectory, ManifestFileName);
            JsonUtility.Serialize(manifestPath, manifest);
            Logger.Log(LogLevel.Verbose, $"Manifest file saved to {manifestPath}.");
        }
Example #27
0
 public void ProcessTemplateAndTheme(DocumentBuildContext context, string outputDirectory, bool overwrite)
 {
     ProcessTemplate(context, outputDirectory);
     ProcessTheme(outputDirectory, overwrite);
 }
Example #28
0
 private static void HandleToc(DocumentBuildContext context, SaveResult result)
 {
     if (result.TocMap?.Count > 0)
     {
         foreach (var toc in result.TocMap)
         {
             HashSet<string> list;
             if (context.TocMap.TryGetValue(toc.Key, out list))
             {
                 foreach (var item in toc.Value)
                 {
                     list.Add(item);
                 }
             }
             else
             {
                 context.TocMap[toc.Key] = toc.Value;
             }
         }
     }
 }
Example #29
0
 private void HandleSaveResult(
     DocumentBuildContext context,
     HostService hostService,
     FileModel model,
     SaveResult result)
 {
     context.FileMap[((RelativePath)model.OriginalFileAndType.File).GetPathFromWorkingFolder()] = ((RelativePath)model.File).GetPathFromWorkingFolder();
     DocumentException.RunAll(
         () => CheckFileLink(hostService, model, result),
         () => HandleUids(context, model, result),
         () => HandleToc(context, result),
         () => RegisterXRefSpec(context, model, result),
         () => RegisterManifest(context, model, result));
 }
Example #30
0
 private static void HandleUids(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     foreach (var uid in model.Uids)
     {
         context.UidMap[uid] = ((RelativePath)model.File).GetPathFromWorkingFolder();
     }
     if (result.LinkToUids.Count > 0)
     {
         foreach(var item in result.LinkToUids)
         {
             HashSet<string> files;
             if (context.XRef.TryGetValue(item.Key, out files))
             {
                 files.UnionWith(item.Value);
             }
             else
             {
                 context.XRef[item.Key] = item.Value;
             }
         }
     }
 }
Example #31
0
 private static void HandleUids(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     if (result.LinkToUids.Count > 0)
     {
         context.XRef.UnionWith(result.LinkToUids);
     }
 }
Example #32
0
        public void Build(DocumentBuildParameters parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }
            if (parameters.OutputBaseDir == null)
            {
                throw new ArgumentException("Output folder cannot be null.", nameof(parameters) + "." + nameof(parameters.OutputBaseDir));
            }
            if (parameters.Files == null)
            {
                throw new ArgumentException("Source files cannot be null.", nameof(parameters) + "." + nameof(parameters.Files));
            }
            if (parameters.Metadata == null)
            {
                parameters.Metadata = ImmutableDictionary<string, object>.Empty;
            }

            using (new LoggerPhaseScope(PhaseName))
            {
                Directory.CreateDirectory(parameters.OutputBaseDir);
                var context = new DocumentBuildContext(
                    Path.Combine(Environment.CurrentDirectory, parameters.OutputBaseDir),
                    parameters.Files.EnumerateFiles(),
                    parameters.ExternalReferencePackages,
                    parameters.TemplateCollection
                    );
                Logger.LogInfo("Start building document...");
                IEnumerable<InnerBuildContext> innerContexts = Enumerable.Empty<InnerBuildContext>();
                try
                {
                    innerContexts = GetInnerContexts(parameters, Processors).ToList();
                    foreach (var item in innerContexts)
                    {
                        BuildCore(item.HostService, item.Processor, context);
                    }
                    foreach (var item in innerContexts)
                    {
                        UpdateHref(item.HostService, item.Processor, context);
                    }

                    UpdateContext(context);
                    if (parameters.ExportRawModel)
                    {
                        Logger.LogInfo("Start exporting raw model...");
                        foreach(var item in context.Manifest)
                        {
                            var model = item.Model;
                            if (model.Content != null)
                            {
                                var rawModelPath = Path.Combine(model.BaseDir, Path.ChangeExtension(model.File, RawModelExtension));
                                JsonUtility.Serialize(rawModelPath, model.Content);
                            }
                        }
                    }

                    Transform(context, parameters.TemplateCollection, parameters.ExportViewModel);
                }
                finally
                {
                    foreach (var item in innerContexts)
                    {
                        if (item.HostService != null)
                        {
                            Cleanup(item.HostService);
                            item.HostService.Dispose();
                        }
                    }
                }

                Logger.LogInfo("Building document completed.");
            }
        }
Example #33
0
        private IEnumerable <ManifestItemWithContext> BuildCore(InnerBuildContext buildContext, DocumentBuildContext context)
        {
            var processor   = buildContext.Processor;
            var hostService = buildContext.HostService;

            Logger.LogVerbose($"Plug-in {processor.Name}: Loading document...");
            hostService.SourceFiles = context.AllSourceFiles;
            foreach (var m in hostService.Models)
            {
                if (m.LocalPathFromRepoRoot == null)
                {
                    m.LocalPathFromRepoRoot = Path.Combine(m.BaseDir, m.File).ToDisplayPath();
                }
            }
            var steps = string.Join("=>", processor.BuildSteps.OrderBy(step => step.BuildOrder).Select(s => s.Name));

            Logger.LogInfo($"Building {hostService.Models.Count} file(s) in {processor.Name}({steps})...");
            Logger.LogVerbose($"Plug-in {processor.Name}: Preprocessing...");
            Prebuild(processor, hostService);
            Logger.LogVerbose($"Plug-in {processor.Name}: Building...");
            BuildArticle(processor, hostService);
            Logger.LogVerbose($"Plug-in {processor.Name}: Postprocessing...");
            Postbuild(processor, hostService);
            Logger.LogVerbose($"Plug-in {processor.Name}: Generating manifest...");
            return(ExportManifest(buildContext, context));
        }
Example #34
0
 private void BuildCore(HostService hostService, IDocumentProcessor processor, DocumentBuildContext context)
 {
     Logger.LogInfo($"Plug-in {processor.Name}: Loading document...");
     hostService.SourceFiles = context.AllSourceFiles;
     foreach (var m in hostService.Models)
     {
         if (m.LocalPathFromRepoRoot == null)
         {
             m.LocalPathFromRepoRoot = Path.Combine(m.BaseDir, m.File);
         }
     }
     Logger.LogInfo($"Plug-in {processor.Name}: Document loaded (count = {hostService.Models.Count}).");
     Logger.LogInfo($"Plug-in {processor.Name}: Preprocessing...");
     Prebuild(processor, hostService);
     Logger.LogInfo($"Plug-in {processor.Name}: Building...");
     BuildArticle(processor, hostService);
     Logger.LogInfo($"Plug-in {processor.Name}: Postprocessing...");
     Postbuild(processor, hostService);
     Logger.LogInfo($"Plug-in {processor.Name}: Saving...");
     Save(processor, hostService, context);
 }
Example #35
0
 private void BuildCore(
     IDocumentProcessor processor,
     IEnumerable<FileAndType> files,
     ImmutableDictionary<string, object> metadata,
     FileMetadata fileMetadata,
     DocumentBuildContext context)
 {
     Logger.LogInfo($"Plug-in {processor.Name}: Loading document...");
     using (var hostService = new HostService(
         from file in files
         select Load(processor, metadata, fileMetadata, file)))
     {
         hostService.SourceFiles = context.AllSourceFiles;
         foreach (var m in hostService.Models)
         {
             if (m.LocalPathFromRepoRoot == null)
             {
                 m.LocalPathFromRepoRoot = Path.Combine(m.BaseDir, m.File);
             }
         }
         Logger.LogInfo($"Plug-in {processor.Name}: Document loaded (count = {hostService.Models.Count}).");
         Logger.LogInfo($"Plug-in {processor.Name}: Preprocessing...");
         Prebuild(processor, hostService);
         Logger.LogInfo($"Plug-in {processor.Name}: Building...");
         BuildArticle(processor, hostService);
         Logger.LogInfo($"Plug-in {processor.Name}: Postprocessing...");
         Postbuild(processor, hostService);
         Logger.LogInfo($"Plug-in {processor.Name}: Saving...");
         Save(processor, hostService, context);
     }
 }
Example #36
0
        private void UpdateContext(DocumentBuildContext context)
        {
            //update internal XrefMap
            if (context.XRefSpecMap != null)
            {
                foreach (var pair in context.XRefSpecMap)
                {
                    string targetFilePath;
                    if (context.FileMap.TryGetValue(pair.Value.Href, out targetFilePath))
                    {
                        pair.Value.Href = targetFilePath;
                    }
                    else
                    {
                        Logger.LogWarning($"{pair.Value.Href} is not found in .filemap");
                    }
                }
            }

            context.SetExternalXRefSpec();
        }
Example #37
0
 private void Save(IDocumentProcessor processor, HostService hostService, DocumentBuildContext context)
 {
     hostService.Models.RunAll(
         m =>
         {
             try
             {
                 if (m.Type != DocumentType.Override)
                 {
                     using (new LoggerFileScope(m.OriginalFileAndType.File))
                     {
                         Logger.LogVerbose($"Plug-in {processor.Name}: Saving...");
                         m.BaseDir = context.BuildOutputFolder;
                         var result = processor.Save(m);
                         if (result != null)
                         {
                             HandleSaveResult(context, hostService, m, result);
                         }
                     }
                 }
             }
             finally
             {
                 m.Dispose();
             }
         });
 }
Example #38
0
 private static void RegisterManifest(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     context.Manifest.Add(new ManifestItem
     {
         DocumentType = result.DocumentType,
         ModelFile = result.ModelFile,
         ResourceFile = result.ResourceFile,
         OriginalFile = model.OriginalFileAndType.File,
         // TODO: What is API doc's LocalPathToRepo? => defined in ManagedReferenceDocumentProcessor
         LocalPathFromRepoRoot = model.LocalPathFromRepoRoot
     });
 }
Example #39
0
 private static void HandleUids(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     foreach (var uid in model.Uids)
     {
         context.UidMap[uid] = ((RelativePath)model.File).GetPathFromWorkingFolder();
     }
     if (result.LinkToUids.Length > 0)
     {
         context.XRef.UnionWith(result.LinkToUids);
     }
 }
Example #40
0
        private void TranformHtml(DocumentBuildContext context, string transformed, string relativeModelPath, string outputPath)
        {
            // Update HREF and XREF
            HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument();
            html.LoadHtml(transformed);
            var srcNodes = html.DocumentNode.SelectNodes("//*/@src");
            if (srcNodes != null)
                foreach (var link in srcNodes)
                {
                    UpdateSrc(link, context.FileMap, s => UpdateFilePath(s, relativeModelPath));
                }

            var hrefNodes = html.DocumentNode.SelectNodes("//*/@href");
            if (hrefNodes != null)
                foreach (var link in hrefNodes)
                {
                    // xref is generated by docfx, and is lower-cased
                    if (link.Name == "xref")
                    {
                        UpdateXref(link, context.XRefSpecMap, context.ExternalXRefSpec, s => UpdateFilePath(s, relativeModelPath), Language);
                    }
                    else
                    {
                        UpdateHref(link, context.FileMap, s => UpdateFilePath(s, relativeModelPath));
                    }
                }

            // Save with extension changed
            var subDirectory = Path.GetDirectoryName(outputPath);
            if (!string.IsNullOrEmpty(subDirectory) && !Directory.Exists(subDirectory)) Directory.CreateDirectory(subDirectory);
            html.Save(outputPath, Encoding.UTF8);
        }
Example #41
0
 private void RegisterXRefSpec(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     foreach (var spec in result.XRefSpecs)
     {
         if (!string.IsNullOrWhiteSpace(spec?.Uid))
         {
             if (context.XRefSpecMap.ContainsKey(spec.Uid))
             {
                 Logger.LogWarning($"Uid({spec.Uid}) duplicated.", file: model.LocalPathFromRepoRoot);
             }
             else
             {
                 context.XRefSpecMap[spec.Uid] = spec.ToReadOnly();
             }
         }
     }
 }
Example #42
0
        private void UpdateHref(HostService hostService, IDocumentProcessor processor, DocumentBuildContext context)
        {
            Func <string, string, string> updater = (originalPathToFile, filePathToRoot) =>
            {
                string href;
                if (string.IsNullOrEmpty(originalPathToFile) || !context.FileMap.TryGetValue(originalPathToFile, out href))
                {
                    return(originalPathToFile);
                }
                var relativePath = ((RelativePath)href).MakeRelativeTo(((RelativePath)filePathToRoot).GetPathFromWorkingFolder());
                return(relativePath);
            };

            hostService.Models.RunAll(
                m =>
            {
                using (new LoggerFileScope(m.OriginalFileAndType.File))
                {
                    Logger.LogVerbose($"Plug-in {processor.Name}: Updating href...");
                    processor.UpdateHref(m, updater);
                }
            });
        }
Example #43
0
 private void BuildCore(HostService hostService, IDocumentProcessor processor, DocumentBuildContext context)
 {
     Logger.LogInfo($"Plug-in {processor.Name}: Loading document...");
     hostService.SourceFiles = context.AllSourceFiles;
     foreach (var m in hostService.Models)
     {
         if (m.LocalPathFromRepoRoot == null)
         {
             m.LocalPathFromRepoRoot = Path.Combine(m.BaseDir, m.File);
         }
     }
     Logger.LogInfo($"Plug-in {processor.Name}: Document loaded (count = {hostService.Models.Count}).");
     Logger.LogInfo($"Plug-in {processor.Name}: Preprocessing...");
     Prebuild(processor, hostService);
     Logger.LogInfo($"Plug-in {processor.Name}: Building...");
     BuildArticle(processor, hostService);
     Logger.LogInfo($"Plug-in {processor.Name}: Postprocessing...");
     Postbuild(processor, hostService);
     Logger.LogInfo($"Plug-in {processor.Name}: Saving...");
     Save(processor, hostService, context);
 }
Example #44
0
 private void Save(IDocumentProcessor processor, HostService hostService, DocumentBuildContext context)
 {
     hostService.Models.RunAll(
         m =>
         {
             if (m.Type != DocumentType.Override)
             {
                 using (new LoggerFileScope(m.OriginalFileAndType.File))
                 {
                     Logger.LogVerbose($"Plug-in {processor.Name}: Saving...");
                     m.BaseDir = context.BuildOutputFolder;
                     if (m.PathRewriter != null)
                     {
                         m.File = m.PathRewriter(m.File);
                     }
                     var result = processor.Save(m);
                     if (result != null)
                     {
                         m.File = TemplateProcessor.UpdateFilePath(m.File, result.DocumentType, context.TemplateCollection);
                         result.ModelFile = TemplateProcessor.UpdateFilePath(result.ModelFile, result.DocumentType, context.TemplateCollection);
                         HandleSaveResult(context, hostService, m, result);
                     }
                 }
             }
         });
 }
Example #45
0
        public void Process(DocumentBuildContext context, string outputDirectory)
        {
            var baseDirectory = context.BuildOutputFolder;

            if (string.IsNullOrEmpty(outputDirectory)) outputDirectory = Environment.CurrentDirectory;
            if (string.IsNullOrEmpty(baseDirectory)) baseDirectory = Environment.CurrentDirectory;

            if (!Directory.Exists(outputDirectory)) Directory.CreateDirectory(outputDirectory);

            // 1. Copy dependent files with path relative to the base output directory
            ProcessDependencies(outputDirectory);
            Dictionary<string, HashSet<string>> unProcessedType = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
            Dictionary<string, string> extMapping = new Dictionary<string, string>();
            // 2. Get extension for each item
            foreach (var item in context.Manifest)
            {
                if (item.ModelFile == null) throw new ArgumentNullException("Model file path must be specified!");
                if (item.DocumentType == null) throw new ArgumentNullException($"Document type is not allowed to be NULL for ${item.ModelFile}!");
                // NOTE: Resource is not supported for applying templates
                if (item.DocumentType.Equals("Resource", StringComparison.OrdinalIgnoreCase)) continue;
                var templates = _templates[item.DocumentType];
                // Get default template extension
                if (templates == null || templates.Count == 0)
                {
                    HashSet<string> unProcessedFiles;
                    if (unProcessedType.TryGetValue(item.DocumentType, out unProcessedFiles))
                    {
                        unProcessedFiles.Add(item.ModelFile);
                    }
                    else
                    {
                        unProcessedType[item.DocumentType] = new HashSet<string>(FilePathComparer.OSPlatformSensitiveComparer) { item.ModelFile };
                    }
                }
                else
                {
                    var defaultTemplate = templates.FirstOrDefault(s => s.IsPrimary) ?? templates[0];
                    string key = ((RelativePath)item.OriginalFile).GetPathFromWorkingFolder();
                    string value;
                    if (context.FileMap.TryGetValue(key, out value))
                    {
                        context.FileMap[key] = Path.ChangeExtension(value, defaultTemplate.Extension);
                        extMapping[key] = defaultTemplate.Extension;
                    }
                    else
                    {
                        Logger.Log(LogLevel.Warning, $"{key} is not found in .filemap");
                    }
                }
            }

            //update internal XrefMap
            if (context.XRefSpecMap != null)
            {
                foreach (var pair in context.XRefSpecMap)
                {
                    string ext;
                    if (extMapping.TryGetValue(pair.Value.Href, out ext))
                    {
                        pair.Value.Href = Path.ChangeExtension(pair.Value.Href, ext);
                    }
                }
            }

            if (unProcessedType.Count > 0)
            {
                StringBuilder sb = new StringBuilder("There is no template processing:");
                foreach (var type in unProcessedType)
                {
                    sb.AppendLine($"- Document type: \"{type.Key}\"");
                    sb.AppendLine($"- Files:");
                    foreach (var file in type.Value)
                    {
                        sb.AppendLine($"  -\"{file}\"");
                    }
                }
                Logger.Log(LogLevel.Warning, sb.ToString());// not processed but copied to '{modelOutputPath}'");
            }

            List<TemplateManifestItem> manifest = new List<TemplateManifestItem>();

            // 3. Process every model and save to output directory
            foreach (var item in context.Manifest)
            {
                var manifestItem = new TemplateManifestItem
                {
                    DocumentType = item.DocumentType,
                    OriginalFile = item.LocalPathFromRepoRoot,
                    OutputFiles = new Dictionary<string, string>()
                };
                try
                {
                    var templates = _templates[item.DocumentType];
                    // 1. process model
                    if (templates == null)
                    {
                        // TODO: what if template to transform the type is not found? DO NOTHING?
                        // CopyFile(modelFile, modelOutputPath);
                    }
                    else
                    {
                        var modelFile = Path.Combine(baseDirectory, item.ModelFile);
                        var systemAttrs = new SystemAttributes(context, item, TemplateProcessor.Language);
                        foreach (var template in templates)
                        {
                            var extension = template.Extension;
                            string outputFile = Path.ChangeExtension(item.ModelFile, extension);
                            string outputPath = Path.Combine(outputDirectory ?? string.Empty, outputFile);
                            var dir = Path.GetDirectoryName(outputPath);
                            if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);
                            var transformed = template.Transform(modelFile, systemAttrs);
                            if (!string.IsNullOrWhiteSpace(transformed))
                            {
                                if (extension.Equals(".html", StringComparison.OrdinalIgnoreCase))
                                {
                                    TranformHtml(context, transformed, item.ModelFile, outputPath);
                                }
                                else
                                {
                                    File.WriteAllText(outputPath, transformed, Encoding.UTF8);
                                }

                                Logger.Log(LogLevel.Verbose, $"Transformed model \"{item.ModelFile}\" to \"{outputPath}\".");
                            }
                            else
                            {
                                // TODO: WHAT to do if is transformed to empty string? STILL creat empty file?
                                Logger.Log(LogLevel.Warning, $"Model \"{item.ModelFile}\" is transformed to empty string with template \"{template.Name}\"");
                                File.WriteAllText(outputPath, string.Empty);
                            }
                            manifestItem.OutputFiles.Add(extension, outputFile);
                        }
                    }

                    // 2. process resource
                    if (item.ResourceFile != null)
                    {
                        manifestItem.OutputFiles.Add("resource", item.ResourceFile);
                        PathUtility.CopyFile(Path.Combine(baseDirectory, item.ResourceFile), Path.Combine(outputDirectory, item.ResourceFile), true);
                    }
                }
                catch (Exception e)
                {
                    Logger.Log(LogLevel.Warning, $"Unable to transform {item.ModelFile}: {e.Message}. Ignored.");
                }
                manifest.Add(manifestItem);
            }

            // Save manifest
            var manifestPath = Path.Combine(outputDirectory, ManifestFileName);
            JsonUtility.Serialize(manifestPath, manifest);
            Logger.Log(LogLevel.Verbose, $"Manifest file saved to {manifestPath}.");
        }
Example #46
0
        public void Build(DocumentBuildParameters parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }
            if (parameters.OutputBaseDir == null)
            {
                throw new ArgumentException("Output folder cannot be null.", nameof(parameters) + "." + nameof(parameters.OutputBaseDir));
            }
            if (parameters.Files == null)
            {
                throw new ArgumentException("Source files cannot be null.", nameof(parameters) + "." + nameof(parameters.Files));
            }
            if (parameters.Metadata == null)
            {
                parameters.Metadata = ImmutableDictionary <string, object> .Empty;
            }

            using (new LoggerPhaseScope(PhaseName))
            {
                Directory.CreateDirectory(parameters.OutputBaseDir);
                var context = new DocumentBuildContext(
                    Path.Combine(Environment.CurrentDirectory, parameters.OutputBaseDir),
                    parameters.Files.EnumerateFiles(),
                    parameters.ExternalReferencePackages
                    );
                Logger.LogVerbose("Start building document...");
                IEnumerable <InnerBuildContext> innerContexts = Enumerable.Empty <InnerBuildContext>();
                try
                {
                    using (var processor = parameters.TemplateManager?.GetTemplateProcessor())
                    {
                        innerContexts = GetInnerContexts(parameters, Processors, processor).ToList();
                        var manifest = new List <ManifestItemWithContext>();
                        foreach (var item in innerContexts)
                        {
                            manifest.AddRange(BuildCore(item, context));
                        }

                        // Use manifest from now on
                        UpdateContext(context);
                        UpdateHref(manifest, context);

                        TemplateProcessor.Transform(processor, manifest.Select(s => s.Item).ToList(), context, parameters.ApplyTemplateSettings);

                        Logger.LogInfo($"Building {manifest.Count} file(s) completed.");
                    }
                }
                finally
                {
                    foreach (var item in innerContexts)
                    {
                        if (item.HostService != null)
                        {
                            Cleanup(item.HostService);
                            item.HostService.Dispose();
                        }
                    }
                }
            }
        }
Example #47
0
        // TODO: change to use IDocumentBuildContext
        public static TemplateManifestItem Transform(DocumentBuildContext context, ManifestItem item, TemplateCollection templateCollection, string outputDirectory, bool exportMetadata, Func<string, string> metadataFilePathProvider)
        {
            if (item.Model == null || item.Model.Content == null) throw new ArgumentNullException("Content for item.Model should not be null!");
            var baseDirectory = context.BuildOutputFolder ?? string.Empty;
            var manifestItem = new TemplateManifestItem
            {
                DocumentType = item.DocumentType,
                OriginalFile = item.LocalPathFromRepoRoot,
                OutputFiles = new Dictionary<string, string>()
            };
            HashSet<string> missingUids = new HashSet<string>();
            if (templateCollection == null || templateCollection.Count == 0)
            {
                return manifestItem;
            }
            try
            {
                var model = item.Model.Content;
                var templates = templateCollection[item.DocumentType];
                // 1. process model
                if (templates == null)
                {
                    // Logger.LogWarning($"There is no template processing {item.DocumentType} document \"{item.LocalPathFromRepoRoot}\"");
                }
                else
                {
                    var systemAttrs = new SystemAttributes(context, item, TemplateProcessor.Language);
                    foreach (var template in templates)
                    {
                        var extension = template.Extension;
                        string outputFile = Path.ChangeExtension(item.ModelFile, extension);
                        string outputPath = Path.Combine(outputDirectory ?? string.Empty, outputFile);
                        var dir = Path.GetDirectoryName(outputPath);
                        if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);
                        string transformed;
                        var result = template.TransformModel(model, systemAttrs);

                        if (exportMetadata)
                        {
                            if (metadataFilePathProvider == null)
                            {
                                throw new ArgumentNullException(nameof(metadataFilePathProvider));
                            }

                            JsonUtility.Serialize(metadataFilePathProvider(outputPath), result.Model);
                        }

                        transformed = result.Result;


                        if (!string.IsNullOrWhiteSpace(transformed))
                        {
                            if (extension.Equals(".html", StringComparison.OrdinalIgnoreCase))
                            {
                                try
                                {
                                    TranformHtml(context, transformed, item.ModelFile, outputPath);
                                }
                                catch (AggregateException e)
                                {
                                    e.Handle(s =>
                                    {
                                        var xrefExcetpion = s as CrossReferenceNotResolvedException;
                                        if (xrefExcetpion != null)
                                        {
                                            missingUids.Add(xrefExcetpion.UidRawText);
                                            return true;
                                        }
                                        else
                                        {
                                            return false;
                                        }
                                    });
                                }
                            }
                            else
                            {
                                File.WriteAllText(outputPath, transformed, Encoding.UTF8);
                            }

                            Logger.Log(LogLevel.Verbose, $"Transformed model \"{item.ModelFile}\" to \"{outputPath}\".");
                        }
                        else
                        {
                            // TODO: WHAT to do if is transformed to empty string? STILL creat empty file?
                            Logger.LogWarning($"Model \"{item.ModelFile}\" is transformed to empty string with template \"{template.Name}\"");
                            File.WriteAllText(outputPath, string.Empty);
                        }
                        manifestItem.OutputFiles.Add(extension, outputFile);
                    }
                }

                // 2. process resource
                if (item.ResourceFile != null)
                {
                    PathUtility.CopyFile(Path.Combine(baseDirectory, item.ResourceFile), Path.Combine(outputDirectory, item.ResourceFile), true);
                    manifestItem.OutputFiles.Add("resource", item.ResourceFile);
                }
            }
            catch (Exception e)
            {
                Logger.LogError($"Unable to transform {item.ModelFile}: {e.Message}. Ignored.");
                throw;
            }

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

            return manifestItem;
        }
Example #48
0
        public static TemplateManifestItem Transform(DocumentBuildContext context, ManifestItem item, TemplateCollection templateCollection, string outputDirectory, bool exportMetadata, Func<string, string> metadataFilePathProvider)
        {
            var baseDirectory = context.BuildOutputFolder ?? string.Empty;
            var manifestItem = new TemplateManifestItem
            {
                DocumentType = item.DocumentType,
                OriginalFile = item.LocalPathFromRepoRoot,
                OutputFiles = new Dictionary<string, string>()
            };
            if (templateCollection == null || templateCollection.Count == 0)
            {
                return manifestItem;
            }
            try
            {
                var model = item.Model?.Content;
                var templates = templateCollection[item.DocumentType];
                // 1. process model
                if (templates == null)
                {
                    // Logger.LogWarning($"There is no template processing {item.DocumentType} document \"{item.LocalPathFromRepoRoot}\"");
                }
                else
                {
                    var modelFile = Path.Combine(baseDirectory, item.ModelFile);
                    var systemAttrs = new SystemAttributes(context, item, TemplateProcessor.Language);
                    foreach (var template in templates)
                    {
                        var extension = template.Extension;
                        string outputFile = Path.ChangeExtension(item.ModelFile, extension);
                        string outputPath = Path.Combine(outputDirectory ?? string.Empty, outputFile);
                        var dir = Path.GetDirectoryName(outputPath);
                        if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);
                        string transformed;
                        if (model == null)
                        {
                            // TODO: remove
                            // currently keep to pass UT
                            transformed = template.Transform(item.ModelFile, systemAttrs);
                        }
                        else
                        {
                            var result = template.TransformModel(model, systemAttrs);

                            if (exportMetadata)
                            {
                                if (metadataFilePathProvider == null)
                                {
                                    throw new ArgumentNullException(nameof(metadataFilePathProvider));
                                }

                                JsonUtility.Serialize(metadataFilePathProvider(outputPath), result.Model);
                            }

                            transformed = result.Result;
                        }

                        if (!string.IsNullOrWhiteSpace(transformed))
                        {
                            if (extension.Equals(".html", StringComparison.OrdinalIgnoreCase))
                            {
                                TranformHtml(context, transformed, item.ModelFile, outputPath);
                            }
                            else
                            {
                                File.WriteAllText(outputPath, transformed, Encoding.UTF8);
                            }

                            Logger.Log(LogLevel.Verbose, $"Transformed model \"{item.ModelFile}\" to \"{outputPath}\".");
                        }
                        else
                        {
                            // TODO: WHAT to do if is transformed to empty string? STILL creat empty file?
                            Logger.LogWarning($"Model \"{item.ModelFile}\" is transformed to empty string with template \"{template.Name}\"");
                            File.WriteAllText(outputPath, string.Empty);
                        }
                        manifestItem.OutputFiles.Add(extension, outputFile);
                    }
                }

                // 2. process resource
                if (item.ResourceFile != null)
                {
                    PathUtility.CopyFile(Path.Combine(baseDirectory, item.ResourceFile), Path.Combine(outputDirectory, item.ResourceFile), true);
                    manifestItem.OutputFiles.Add("resource", item.ResourceFile);
                }
            }
            catch (Exception e)
            {
                Logger.LogWarning($"Unable to transform {item.ModelFile}: {e.Message}. Ignored.");
            }

            return manifestItem;
        }
Example #49
0
 private void RegisterXRefSpec(DocumentBuildContext context, FileModel model, SaveResult result)
 {
     foreach (var spec in result.XRefSpecs)
     {
         if (!string.IsNullOrWhiteSpace(spec?.Uid))
         {
             XRefSpec xref;
             if (context.XRefSpecMap.TryGetValue(spec.Uid, out xref))
             {
                 Logger.LogWarning($"Uid({spec.Uid}) has already been defined in {((RelativePath)xref.Href).RemoveWorkingFolder()}.", file: model.LocalPathFromRepoRoot);
             }
             else
             {
                 context.XRefSpecMap[spec.Uid] = spec.ToReadOnly();
             }
         }
     }
 }
Example #50
0
 private void UpdateHref(HostService hostService, IDocumentProcessor processor, DocumentBuildContext context)
 {
     Func<string, string, string> updater = (originalPathToFile, filePathToRoot) =>
     {
         string href;
         if (string.IsNullOrEmpty(originalPathToFile) || !context.FileMap.TryGetValue(originalPathToFile, out href))
         {
             return originalPathToFile;
         }
         var relativePath = ((RelativePath)href).MakeRelativeTo(((RelativePath)filePathToRoot).GetPathFromWorkingFolder());
         return relativePath;
     };
     hostService.Models.RunAll(
         m =>
         {
             using (new LoggerFileScope(m.OriginalFileAndType.File))
             {
                 Logger.LogVerbose($"Plug-in {processor.Name}: Updating href...");
                 processor.UpdateHref(m, updater);
             }
         });
 }
Example #51
0
        private IEnumerable <ManifestItemWithContext> ExportManifest(InnerBuildContext buildContext, DocumentBuildContext context)
        {
            var hostService       = buildContext.HostService;
            var processor         = buildContext.Processor;
            var templateProcessor = buildContext.TemplateProcessor;
            var manifestItems     = new List <ManifestItemWithContext>();

            hostService.Models.RunAll(m =>
            {
                if (m.Type != DocumentType.Override)
                {
                    using (new LoggerFileScope(m.LocalPathFromRepoRoot))
                    {
                        Logger.LogVerbose($"Plug-in {processor.Name}: Saving...");
                        m.BaseDir = context.BuildOutputFolder;
                        if (m.PathRewriter != null)
                        {
                            m.File = m.PathRewriter(m.File);
                        }
                        var result = processor.Save(m);
                        if (result != null)
                        {
                            if (templateProcessor != null)
                            {
                                m.File           = templateProcessor.UpdateFileExtension(m.File, result.DocumentType);
                                result.ModelFile = templateProcessor.UpdateFileExtension(result.ModelFile, result.DocumentType);
                            }

                            var item = HandleSaveResult(context, hostService, m, result);
                            manifestItems.Add(new ManifestItemWithContext(item, m, processor));
                        }
                    }
                }
            });
            return(manifestItems);
        }
Example #52
0
        public void Build(DocumentBuildParameters parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }
            if (parameters.OutputBaseDir == null)
            {
                throw new ArgumentException("Output folder cannot be null.", nameof(parameters) + "." + nameof(parameters.OutputBaseDir));
            }
            if (parameters.Files == null)
            {
                throw new ArgumentException("Source files cannot be null.", nameof(parameters) + "." + nameof(parameters.Files));
            }
            if (parameters.Metadata == null)
            {
                parameters.Metadata = ImmutableDictionary <string, object> .Empty;
            }

            using (new LoggerPhaseScope(PhaseName))
            {
                Directory.CreateDirectory(parameters.OutputBaseDir);
                var context = new DocumentBuildContext(
                    Path.Combine(Environment.CurrentDirectory, parameters.OutputBaseDir),
                    parameters.Files.EnumerateFiles(),
                    parameters.ExternalReferencePackages,
                    parameters.TemplateCollection
                    );
                Logger.LogInfo("Start building document...");
                IEnumerable <InnerBuildContext> innerContexts = Enumerable.Empty <InnerBuildContext>();
                try
                {
                    innerContexts = GetInnerContexts(parameters, Processors).ToList();
                    foreach (var item in innerContexts)
                    {
                        BuildCore(item.HostService, item.Processor, context);
                    }
                    foreach (var item in innerContexts)
                    {
                        UpdateHref(item.HostService, item.Processor, context);
                    }

                    UpdateContext(context);
                    if (parameters.ExportRawModel)
                    {
                        Logger.LogInfo("Start exporting raw model...");
                        foreach (var item in context.Manifest)
                        {
                            var model = item.Model;
                            if (model.Content != null)
                            {
                                var rawModelPath = Path.Combine(model.BaseDir, Path.ChangeExtension(model.File, RawModelExtension));
                                JsonUtility.Serialize(rawModelPath, model.Content);
                            }
                        }
                    }

                    Transform(context, parameters.TemplateCollection, parameters.ExportViewModel);
                }
                finally
                {
                    foreach (var item in innerContexts)
                    {
                        if (item.HostService != null)
                        {
                            Cleanup(item.HostService);
                            item.HostService.Dispose();
                        }
                    }
                }

                Logger.LogInfo("Building document completed.");
            }
        }
Example #53
0
 private void UpdateContext(DocumentBuildContext context)
 {
     context.SetExternalXRefSpec();
 }
Example #54
0
 private void UpdateContext(DocumentBuildContext context)
 {
     context.SetExternalXRefSpec();
 }