diff --git a/Project.toml b/Project.toml
index eeff70ca..76089295 100644
--- a/Project.toml
+++ b/Project.toml
@@ -20,10 +20,17 @@ Documenter = "1"
DocumenterCitations = "1"
IOCapture = "0.2"
NodeJS_20_jll = "20"
+Test = "1"
julia = "1.6"
+[extras]
+Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
+
[weakdeps]
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
[extensions]
DocumenterVitepressDocumenterCitationsExt = "DocumenterCitations"
+
+[targets]
+test = ["Test"]
diff --git a/src/writer.jl b/src/writer.jl
index e15892e4..ad6f95b6 100644
--- a/src/writer.jl
+++ b/src/writer.jl
@@ -9,8 +9,8 @@ import Markdown
"""
MarkdownVitepress(; repo, devbranch, devurl, kwargs...)
-This is the main entry point for the Vitepress Markdown writer.
-
+This is the main entry point for the Vitepress Markdown writer.
+
It is a config which can be passed to the `format` keyword argument in `Documenter.makedocs`, and causes it to emit a Vitepress site.
!!! tip "Quick start"
@@ -49,7 +49,7 @@ Base.@kwdef struct MarkdownVitepress <: Documenter.Writer
"""The path to which the Markdown files will be output. Defaults to `\$build/.documenter`."""
md_output_path::String = ".documenter"
"""
- Determines whether to clean up the Markdown assets after build, i.e., whether to remove the contents of `md_output_path` after the Vitepress site is built.
+ Determines whether to clean up the Markdown assets after build, i.e., whether to remove the contents of `md_output_path` after the Vitepress site is built.
Options are:
- `nothing`: **Default**. Only remove the contents of `md_output_path` if the documentation will deploy, to save space.
- `true`: Removes the contents of `md_output_path` after the Vitepress site is built.
@@ -57,7 +57,14 @@ Base.@kwdef struct MarkdownVitepress <: Documenter.Writer
"""
clean_md_output::Union{Nothing, Bool} = nothing
"""
- DeployDecision from Documenter.jl. This is used to determine whether to deploy the documentation or not.
+ Whether to insert 200 redirects from https://example.com/page/ to https://example.com/page.
+
+ Defaults to `false`. This is useful for transitioning from Documenter.jl which uses
+ trailing slashes for its canonical urls by default.
+ """
+ redirect_trailing_slash::Bool = false
+ """
+ `DeployDecision` from Documenter.jl. This is used to determine whether to deploy the documentation or not.
Options are:
- `nothing`: **Default**. Automatically determine whether to deploy the documentation.
- `Documenter.DeployDecision`: Override the automatic decision and deploy based on the passed config.
@@ -66,8 +73,20 @@ Base.@kwdef struct MarkdownVitepress <: Documenter.Writer
`Documenter.deploy_folder(Documenter.auto_detect_deploy_system(); repo, devbranch, devurl, push_preview)`.
"""
deploy_decision::Union{Nothing, Documenter.DeployDecision} = nothing
+
"A list of assets, the same as what is provided to Documenter's HTMLWriter."
assets = nothing
+
+ # This inner constructor serves only to
+ function MarkdownVitepress(args...)
+ args[10] && !args[6] && throw(ArgumentError(
+ """
+ MarkdownVitepress: `redirect_trailing_slash` can only be `true` if `build_vitepress` is also `true`,
+ because redirects are insterted after the site is built.
+ """
+ ))
+ new(args...)
+ end
end
# return the same file with the extension changed to .md
@@ -82,13 +101,13 @@ This function takes the filename `file`, and returns a file path in the `mdfolde
function docpath(file, builddir, mdfolder)
path = relpath(file, builddir)
filename = mdext(path)
- return joinpath(builddir, mdfolder, filename)
+ return joinpath(builddir, mdfolder, filename)
end
"""
render(args...)
-This is the main entry point and recursive function to render a Documenter document to
+This is the main entry point and recursive function to render a Documenter document to
Markdown in the Vitepress flavour. It is called by `Documenter.build` and should not be
called directly.
@@ -161,7 +180,7 @@ function render(doc::Documenter.Document, settings::MarkdownVitepress=MarkdownVi
cp(file, file_destpath; force = true)
end
end
- end
+ end
if any(favicon_files)
for file in files[favicon_files]
file_relpath = relpath(file, joinpath(builddir, settings.md_output_path, "assets"))
@@ -184,6 +203,23 @@ function render(doc::Documenter.Document, settings::MarkdownVitepress=MarkdownVi
end
mkpath(joinpath(builddir, "final_site"))
+
+ # We manually obtain the Documenter deploy configuration,
+ # so we can use it to set Vitepress's settings.
+ if isnothing(settings.deploy_decision)
+ # TODO: make it so that the user does not have to provide a repo url!
+ deploy_config = Documenter.auto_detect_deploy_system()
+ deploy_decision = Documenter.deploy_folder(
+ deploy_config;
+ repo = settings.repo, # this must be the full URL!
+ devbranch = settings.devbranch,
+ devurl = settings.devurl,
+ push_preview=true,
+ )
+ else
+ deploy_decision = settings.deploy_decision
+ end
+
if isfile(joinpath(builddir, settings.md_output_path, ".vitepress", "config.mts"))
touch(joinpath(builddir, settings.md_output_path, ".vitepress", "config.mts"))
end
@@ -224,7 +260,7 @@ function render(doc::Documenter.Document, settings::MarkdownVitepress=MarkdownVi
rm(joinpath(dirname(builddir), "package-lock.json"))
end
end
- # This is only useful if placed in the root of the `docs` folder, and we don't
+ # This is only useful if placed in the root of the `docs` folder, and we don't
# have any names which conflict with Jekyll (beginning with _ or .) in any case.
# touch(joinpath(builddir, "final_site", ".nojekyll"))
@@ -244,6 +280,44 @@ function render(doc::Documenter.Document, settings::MarkdownVitepress=MarkdownVi
@info "DocumenterVitepress: Markdown output cleaned up. Folder looks like: $(readdir(doc.user.build))"
end
+ if settings.redirect_trailing_slash
+ @info "DocumenterVitepress: inserting javascript 200 redirects from https://example.com/page/ to https://example.com/page because `redirect_trailing_slash` is true."
+ for (root, dirs, files) in walkdir(builddir)
+ for file in files
+ name, ext = splitext(file)
+ if ext === ".html" && name ∉ ("404", "index")
+ dir = joinpath(root, name)
+ if !isdir(dir)
+ mkdir(dir)
+ println(((settings.deploy_url, root, builddir, name)))
+ url = "https://"*normpath(joinpath(settings.deploy_url, relpath(root, builddir), name))
+ println(url)
+ open(joinpath(dir, "index.html"), "w") do io
+ write(io, """
+
+
+ Redirecting to ..$name
+
+ """)
+ # The script is equivalent to
+ # ``
+ # but keeps fragments. If Javascript fails for whatever
+ # reason, the meta http-equiv will proc, dropping fragments
+ # If that, too fails, there's an ordinary, human readable
+ # relative link.
+ #
+ # This uses a relative canonical link which is bad form, but
+ # oh well. We don't have access to the full URL until deploy
+ # time.
+ end
+ end
+ end
+ end
+ end
+ end
else
@info """
DocumenterVitepress: did not build Vitepress site because `build_vitepress` was set to `false`.
@@ -339,7 +413,7 @@ function renderdoc(io::IO, mime::MIME"text/plain", node::Documenter.MarkdownAST.
if url !== nothing
# This is how Documenter does it:
# push!(ret.nodes, a[".docs-sourcelink", :target=>"_blank", :href=>url]("source"))
- # so clearly we should be inserting some form of HTML tag here,
+ # so clearly we should be inserting some form of HTML tag here,
# and defining its rendering in CSS?
# TODO: switch to Documenter style here
println(io, "\n", "[source]($url)", "\n")
@@ -407,9 +481,9 @@ function join_multiblock(node::Documenter.MarkdownAST.Node)
for thing in code_blocks
# reset the buffer and push the old code block
if thing.language != current_language
- # Remove this if statement if you want to
+ # Remove this if statement if you want to
# include empty code blocks in the output.
- if isempty(thing.code)
+ if isempty(thing.code)
current_string *= "\n\n"
continue
end
@@ -768,7 +842,7 @@ function render(io::IO, mime::MIME"text/plain", node::Documenter.MarkdownAST.Nod
# Main.@infiltrate
print(io, "\$", math.math, "\$")
end
-# Display math
+# Display math
function render(io::IO, mime::MIME"text/plain", node::Documenter.MarkdownAST.Node, math::MarkdownAST.DisplayMath, page, doc; kwargs...)
# Main.@infiltrate
println(io)
@@ -813,7 +887,7 @@ function render(io::IO, mime::MIME"text/plain", node::Documenter.MarkdownAST.Nod
end
end
# We create this IOBuffer in order to render to it.
- iob = IOBuffer()
+ iob = IOBuffer()
# This will eventually hold the rendered table cells as Strings.
cell_strings = Vector{Vector{String}}()
current_row_vec = String[]
diff --git a/test/runtests.jl b/test/runtests.jl
new file mode 100644
index 00000000..2a3ee55f
--- /dev/null
+++ b/test/runtests.jl
@@ -0,0 +1,5 @@
+using Test, DocumenterVitepress
+
+@test DocumenterVitepress.MarkdownVitepress(; repo = "...", devbranch = "...", devurl = "...") isa DocumenterVitepress.MarkdownVitepress
+@test_throws ArgumentError DocumenterVitepress.MarkdownVitepress(; repo = "...", devbranch = "...", devurl = "...",
+ build_vitepress = false, redirect_trailing_slash = true)