public override void Process(ProcessingStage stage) { if (!Plugin.Enable) { return; } if (stage == ProcessingStage.BeforeLoadingContent) { _urlSet = new SitemapUrlSet(); } else if (stage == ProcessingStage.BeforeProcessingContent) { const string ns = "http://www.sitemaps.org/schemas/sitemap/0.9"; var xmlSerializer = new XmlSerializer(typeof(SitemapUrlSet), ns); var namespaces = new XmlSerializerNamespaces(); namespaces.Add("", ns); var sitemap = new Utf8StringWriter(); xmlSerializer.Serialize(sitemap, _urlSet, namespaces); // Generate sitemap.xml var content = new DynamicContentObject(Site, "/sitemap.xml") { ContentType = ContentType.Xml, Content = sitemap.ToString() }; Site.DynamicPages.Add(content); // Generate robots.txt var robotsContent = new DynamicContentObject(Site, "/robots.txt") { ContentType = ContentType.Txt, Content = $"Sitemap: {Site.Builtins.UrlRef((ContentObject)null, content.Url)}" }; Site.DynamicPages.Add(robotsContent); } }
public override void Process(ProcessingStage stage) { Debug.Assert(stage == ProcessingStage.BeforeProcessingContent); foreach (var taxonomy in List.ScriptObject) { var name = taxonomy.Key; var value = taxonomy.Value; string singular = null; string url = null; ScriptObject map = null; switch (value) { case string valueAsStr: singular = valueAsStr; break; case ScriptObject valueAsObj: singular = valueAsObj.GetSafeValue <string>("singular"); url = valueAsObj.GetSafeValue <string>("url"); map = valueAsObj.GetSafeValue <ScriptObject>("map"); break; case IScriptCustomFunction _: // Skip functions (clear...etc.) continue; } if (string.IsNullOrWhiteSpace(singular)) { // Don't log an error, as we just want to Site.Error($"Invalid singular form [{singular}] of taxonomy [{name}]. Expecting a non empty string"); continue; } // TODO: verify that plural is a valid identifier var tax = Find(name); if (tax != null) { continue; } List.Add(new Taxonomy(this, name, singular, url, map)); } // Convert taxonomies to readonly after initialization List.ScriptObject.Clear(); foreach (var taxonomy in List) { List.ScriptObject.SetValue(taxonomy.Name, taxonomy, true); } foreach (var page in Site.Pages) { var dyn = (DynamicObject)page; foreach (var tax in List) { var termsObj = dyn[tax.Name]; var terms = termsObj as ScriptArray; if (termsObj == null) { continue; } if (terms == null) { Site.Error("Invalid type"); continue; } foreach (var termNameObj in terms) { var termName = termNameObj as string; if (termName == null) { Site.Error("// TODO ERROR ON TERM"); continue; } object termObj; TaxonomyTerm term; if (!tax.Terms.TryGetValue(termName, out termObj)) { termObj = term = new TaxonomyTerm(tax, termName); tax.Terms[termName] = termObj; } else { term = (TaxonomyTerm)termObj; } term.Pages.Add(page); } } } // Update taxonomy computed foreach (var tax in List) { tax.Update(); } // Generate taxonomy pages foreach (var tax in List) { UPath.TryParse(tax.Url, out var taxPath); var section = taxPath.GetFirstDirectory(out var pathInSection); bool hasTerms = false; // Generate a term page for each term in the current taxonomy foreach (var term in tax.Terms.Values.OfType <TaxonomyTerm>()) { // term.Url var content = new DynamicContentObject(Site, term.Url, section) { ScriptObjectLocal = new ScriptObject(), // only used to let layout processor running Layout = tax.Name, LayoutType = "term", ContentType = ContentType.Html }; content.ScriptObjectLocal.SetValue("pages", term.Pages, true); content.ScriptObjectLocal.SetValue("taxonomy", tax, true); content.ScriptObjectLocal.SetValue("term", term, true); foreach (var page in term.Pages) { content.Dependencies.Add(new PageContentDependency(page)); } content.Initialize(); Site.DynamicPages.Add(content); hasTerms = true; } // Generate a terms page for the current taxonomy if (hasTerms) { var content = new DynamicContentObject(Site, tax.Url, section) { ScriptObjectLocal = new ScriptObject(), // only used to let layout processor running Layout = tax.Name, LayoutType = "terms", ContentType = ContentType.Html }; content.ScriptObjectLocal.SetValue("taxonomy", tax, true); content.Initialize(); // TODO: Add dependencies Site.DynamicPages.Add(content); } } }
private void ProcessBundleLinks(BundleObject bundle, Dictionary <UPath, ContentObject> staticFiles) { Dictionary <string, ConcatGroup> concatBuilders = null; if (bundle.Concat) { concatBuilders = new Dictionary <string, ConcatGroup>(); foreach (var type in bundle.UrlDestination) { if (!concatBuilders.ContainsKey(type.Key)) { concatBuilders[type.Key] = new ConcatGroup(type.Key); } } } // Expand wildcard * links for (int i = 0; i < bundle.Links.Count; i++) { var link = bundle.Links[i]; var path = link.Path; var url = link.Url; if (!path.Contains("*")) { continue; } // Always remove the link bundle.Links.RemoveAt(i); var upath = (UPath)path; bool matchingInFileSystem = false; foreach (var file in Site.FileSystem.EnumerateFileSystemEntries(upath.GetDirectory(), upath.GetName())) { var newLink = new BundleLink(bundle, link.Type, (string)file.Path, url + file.Path.GetName(), link.Mode); bundle.Links.Insert(i++, newLink); matchingInFileSystem = true; } if (!matchingInFileSystem) { foreach (var file in Site.MetaFileSystem.EnumerateFileSystemEntries(upath.GetDirectory(), upath.GetName())) { var newLink = new BundleLink(bundle, link.Type, (string)file.Path, url + file.Path.GetName(), link.Mode); bundle.Links.Insert(i++, newLink); } } // Cancel the double i++ i--; } // Collect minifier IContentMinifier minifier = null; if (bundle.Minify) { var minifierName = bundle.Minifier; foreach (var min in Minifiers) { if (minifierName == null || min.Name == minifierName) { minifier = min; break; } } if (minifier == null) { Site.Warning($"Minify is setup for bundle [{bundle.Name}] but no minifiers are registered (Minified requested: {minifierName ?? "default"})"); } } // Process links for (int i = 0; i < bundle.Links.Count; i++) { var link = bundle.Links[i]; var path = link.Path; var url = link.Url; if (url != null) { if (!UPath.TryParse(url, out _)) { Site.Error($"Invalid absolute url [{url}] in bundle [{bundle.Name}]"); } } if (path != null) { path = ((UPath)path).FullName; link.Path = path; ContentObject currentContent; var isExistingContent = staticFiles.TryGetValue(path, out currentContent); if (url == null) { var outputUrlDirectory = bundle.UrlDestination[link.Type]; // If the file is private or meta, we need to copy to the output // bool isFilePrivateOrMeta = Site.IsFilePrivateOrMeta(entry.FullName); url = outputUrlDirectory + Path.GetFileName(path); link.Url = url; } FileEntry entry = null; // Process file by existing processors if (currentContent == null) { // Check first site, then meta entry = new FileEntry(Site.FileSystem, path); if (!entry.Exists) { entry = new FileEntry(Site.MetaFileSystem, path); } if (entry.Exists) { currentContent = new FileContentObject(Site, entry); } else { Site.Error($"Unable to find content [{path}] in bundle [{bundle.Name}]"); } } if (currentContent != null) { currentContent.Url = url; var listTemp = new PageCollection() { currentContent }; Site.Content.ProcessPages(listTemp, false); link.ContentObject = currentContent; bool isRawContent = link.Type == BundleObjectProperties.ContentType; // If we require concat and/or minify, we preload the content of the file if (!isRawContent && (bundle.Concat || bundle.Minify)) { try { link.Content = currentContent.Content ?? entry.ReadAllText(); // Minify content separately if (bundle.Minify && minifier != null) { Minify(minifier, link, bundle.MinifyExtension); } } catch (Exception ex) { Site.Error($"Unable to load content [{path}] while trying to concatenate for bundle [{bundle.Name}]. Reason: {ex.GetReason()}"); } } // Remove sourcemaps (TODO: make this configurable) RemoveSourceMaps(link); // If we are concatenating if (!isRawContent && concatBuilders != null) { currentContent.Discard = true; // Remove this link from the list of links, as we are going to squash them after bundle.Links.RemoveAt(i); i--; concatBuilders[link.Type].Pages.Add(currentContent); concatBuilders[link.Type].AppendContent(link.Mode, link.Content); } else if (!isExistingContent) { Site.StaticFiles.Add(currentContent); staticFiles.Add(path, currentContent); } } } } // Concatenate files if necessary if (concatBuilders != null) { foreach (var builderGroup in concatBuilders) { foreach (var contentPerMode in builderGroup.Value.ModeToBuilders) { var mode = contentPerMode.Key; var builder = contentPerMode.Value; if (builder.Length > 0) { var type = builderGroup.Key; var outputUrlDirectory = bundle.UrlDestination[type]; // If the file is private or meta, we need to copy to the output // bool isFilePrivateOrMeta = Site.IsFilePrivateOrMeta(entry.FullName); var url = outputUrlDirectory + bundle.Name + (string.IsNullOrEmpty(mode) ? $".{type}" : $"-{mode}.{type}"); var newStaticFile = new DynamicContentObject(Site, url) { Content = builder.ToString() }; Site.DynamicPages.Add(newStaticFile); // Add file dependencies foreach (var page in builderGroup.Value.Pages) { newStaticFile.Dependencies.Add(new PageContentDependency(page)); } var link = new BundleLink(bundle, type, null, url, mode) { Content = newStaticFile.Content, ContentObject = newStaticFile }; bundle.Links.Add(link); } } } } foreach (var link in bundle.Links) { var contentObject = link.ContentObject; if (contentObject != null) { link.Url = contentObject.Url; } } }