This repository has been archived by the owner on Jan 26, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Relativize.scala
84 lines (78 loc) · 3.18 KB
/
Relativize.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package sbtdocusaurus.internal
import java.net.URI
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.SimpleFileVisitor
import java.nio.file.attribute.BasicFileAttributes
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import scala.collection.JavaConverters._
object Relativize {
def htmlSite(site: Path): Unit = {
Files.walkFileTree(
site,
new SimpleFileVisitor[Path] {
override def visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult = {
if (file.getFileName.toString.endsWith(".html")) {
processHtmlFile(site, file)
}
super.visitFile(file, attrs)
}
}
)
}
// actual host name doesn't matter
private val baseUri = URI.create("http://example.com/")
def processHtmlFile(site: Path, file: Path): Unit = {
val originRelativeUri = relativeUri(site.relativize(file))
val originUri = baseUri.resolve(originRelativeUri)
val originPath = Paths.get(originUri.getPath).getParent
def relativizeAttribute(element: Element, attribute: String): Unit = {
val absoluteHref = URI.create(element.attr(s"abs:$attribute"))
if (absoluteHref.getHost == baseUri.getHost) {
val hrefPath = Paths.get(absoluteHref.getPath)
val relativeHref = {
val relativePath = originPath.relativize(hrefPath)
val absolutePath = file.getParent.resolve(relativePath)
val isDirectory = Files.isDirectory(absolutePath)
if (isDirectory) relativePath.resolve("index.html")
else relativePath
}
val fragment =
if (absoluteHref.getFragment == null) ""
else "#" + absoluteHref.getFragment
val newHref = relativeUri(relativeHref).toString + fragment
element.attr(attribute, newHref)
} else if (element.attr(attribute).startsWith("//")) {
// We force "//hostname" links to become "https://hostname" in order to make
// the site browsable without file server. If we keep "//hostname" unchanged
// then users will try to load "file://hostname" which results in 404.
// We hardcode https instead of http because it's OK to load https from http
// but not the other way around.
element.attr(attribute, "https:" + element.attr(attribute))
}
}
val doc = Jsoup.parse(file.toFile, StandardCharsets.UTF_8.name(), originUri.toString)
def relativizeElement(element: String, attribute: String): Unit =
doc.select(element).forEach { element =>
relativizeAttribute(element, attribute)
}
relativizeElement("a", "href")
relativizeElement("link", "href")
relativizeElement("img", "src")
val renderedHtml = doc.outerHtml()
Files.write(file, renderedHtml.getBytes(StandardCharsets.UTF_8))
}
private def relativeUri(relativePath: Path): URI = {
require(!relativePath.isAbsolute, relativePath)
val names = relativePath.iterator().asScala
val uris = names.map { name =>
new URI(null, null, name.toString, null)
}
URI.create(uris.mkString("", "/", ""))
}
}