in functions/src/content.ts [48:201]
private sanitizeHtml(
repoId: string,
page: string,
config: ProjectConfig,
html: string,
branch: string
): string {
// Links
// * Links to page content files should go to our page
// * Links to source files should go to github
//
// Images
// * Images and other things should be made into githubusercontent links
// * Remove badges
let pageDir = "";
if (page) {
const lastSlash = page.lastIndexOf("/");
pageDir = page.substring(0, lastSlash);
if (lastSlash >= 0) {
pageDir = page.substring(0, lastSlash);
}
}
const projectBaseUrl = this.getProjectBaseUrl(repoId);
// TODO: Dynamic branch
const renderedBaseUrl = this.getRenderedContentBaseUrl(repoId, branch);
const rawBaseUrl = urljoin(
Github.getRawContentBaseUrl(repoId, branch),
pageDir
);
const $: CheerioStatic = cheerio.load(html);
// Make all code sections prettyprinted
$("pre > code").each((_: number, el: CheerioElement) => {
$(el).addClass("prettyprint");
});
// Resolve all relative links to github
const that = this;
$("a").each((_: number, el: CheerioElement) => {
const href = el.attribs["href"];
if (!href) {
return;
}
if (that._isGithubLink(href)) {
// Convert github.com/org/foo links to firebaseopensource links
const hrefUrl = url.parse(href);
const pathSegments = hrefUrl.pathname
.split("/")
.filter((seg: string) => seg.trim().length > 0);
if (pathSegments.length === 2) {
const org = pathSegments[0];
const repo = pathSegments[1];
if (!that._isIncludedProject(org, repo)) {
return;
}
const newLink = "/projects/" + pathSegments.join("/") + "/";
Logger.debug(repoId, `Replacing ${href} with ${newLink}.`);
el.attribs["href"] = newLink.toLowerCase();
}
}
if (that._isRelativeLink(href)) {
// Check if the link is to a page within the repo
const repoRelative = path.join(pageDir, href);
const pageKeys = config.pages
? config.pages.map(page => page.path)
: [];
Logger.debug(
repoId,
`Relative link on page ${page}: ${href} --> ${repoRelative}`
);
el.attribs["href"] = repoRelative;
const repoRelativeWithoutHash =
repoRelative.indexOf("#") >= 0
? repoRelative.substring(0, repoRelative.indexOf("#"))
: repoRelative;
const isProjectPage = pageKeys.indexOf(repoRelativeWithoutHash) >= 0;
if (isProjectPage) {
that.lowercaseLink(el);
that.deMarkdownLink(el);
that.sanitizeRelativeLink(el, "href", projectBaseUrl);
Logger.debug(
repoId,
`Sanitizing relative project link ${repoRelative} --> ${
el.attribs["href"]
}`
);
} else {
that.sanitizeRelativeLink(el, "href", renderedBaseUrl);
Logger.debug(
repoId,
`Sanitizing relative GitHub link ${repoRelative} --> ${
el.attribs["href"]
}`
);
}
}
});
// Resolve all relative images, add class to parent
$("img").each((_: number, el: CheerioElement) => {
const src = el.attribs["src"];
if (!src) {
return;
}
const badgePatterns = [
"travis-ci.org",
"shields.io",
"coveralls.io",
"badge.fury.io",
"gitter.im",
"circleci.com",
"opencollective.com",
"cirrus-ci.com",
"sonarcloud.io",
"codecov.io",
"release-notes.com",
/github\.com\/.*\/workflows\/.*\.svg/,
"awesome.re"
];
const isBadge = badgePatterns.some(pattern => {
return !!src.match(pattern);
});
if (isBadge) {
// Mark Badges
$(el).addClass("img-badge");
} else {
// Add the image-parent class to the parent
$(el)
.parent()
.addClass("img-parent");
}
that.sanitizeRelativeLink(el, "src", rawBaseUrl);
});
return $.html();
}