Skip to content

Commit 80b1116

Browse files
committed
feat(Builder): relativize helper
1 parent e545dfe commit 80b1116

File tree

2 files changed

+95
-84
lines changed

2 files changed

+95
-84
lines changed

src/lib/Gen/hbs/Builder.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,102 @@ loadPartials(
6767
exp.error().Throw();
6868
}
6969
}
70+
71+
/* Make a URL relative to another URL.
72+
73+
This function is a version of the Antora `relativize` helper,
74+
used to create relative URLs between two paths in Antora projects.
75+
76+
The function takes two paths, `to` and `from`, and returns a
77+
relative path from `from` to `to`.
78+
79+
If `from` is not provided, then the URL of the symbol being
80+
rendered is used as the `from` path.
81+
82+
@see https://gitlab.com/antora/antora-ui-default/-/blob/master/src/helpers/relativize.js
83+
*/
84+
dom::Value
85+
relativize_fn(dom::Value to0, dom::Value from0, dom::Value options)
86+
{
87+
if (!to0)
88+
{
89+
return "#";
90+
}
91+
92+
if (!to0.isString())
93+
{
94+
return to0;
95+
}
96+
97+
std::string_view to = to0.getString().get();
98+
if (!to.starts_with('/'))
99+
{
100+
return to0;
101+
}
102+
103+
// Single argument invocation
104+
bool const singleArg = !options;
105+
if (singleArg)
106+
{
107+
// NOTE only legacy invocation provides both to and from0
108+
options = from0;
109+
from0 = options.lookup("data.root.symbol.url");
110+
}
111+
112+
// If `from` is still not set as a string
113+
if (!from0.isString() || from0.getString().empty())
114+
{
115+
return to;
116+
}
117+
std::string_view from = from0.getString().get();
118+
119+
// Find anchor in URL
120+
std::string_view hash;
121+
std::size_t hashIdx = to.find('#');
122+
if (hashIdx != std::string_view::npos)
123+
{
124+
hash = to.substr(hashIdx);
125+
to = to.substr(0, hashIdx);
126+
}
127+
128+
// Handle the case where they are the same URL
129+
if (to == from)
130+
{
131+
if (!hash.empty())
132+
{
133+
return hash;
134+
}
135+
else if (files::isDirsy(to))
136+
{
137+
return "./";
138+
}
139+
return files::getFileName(to);
140+
}
141+
142+
// Handle the general case
143+
std::string fromDir = files::getParentDir(from);
144+
std::string relativePath = std::filesystem::path(to).lexically_relative(fromDir).generic_string();
145+
if (relativePath.empty())
146+
{
147+
relativePath = ".";
148+
}
149+
if (!relativePath.starts_with("../") && !relativePath.starts_with("./"))
150+
{
151+
relativePath = "./" + relativePath;
152+
}
153+
relativePath += hash;
154+
155+
if (relativePath == "/boost.adoc")
156+
{
157+
relativePath = "." + relativePath;
158+
}
159+
return relativePath;
70160
}
71161

162+
} // (anon)
163+
164+
165+
72166
Builder::
73167
Builder(
74168
HandlebarsCorpus const& corpus,
@@ -143,6 +237,7 @@ Builder(
143237
helpers::registerAntoraHelpers(hbs_);
144238
helpers::registerLogicalHelpers(hbs_);
145239
helpers::registerContainerHelpers(hbs_);
240+
hbs_.registerHelper("relativize", dom::makeInvocable(relativize_fn));
146241

147242
// load templates
148243
exp = forEachFile(layoutDir(), false,

src/lib/Support/Handlebars.cpp

Lines changed: 0 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3812,7 +3812,6 @@ registerAntoraHelpers(Handlebars& hbs)
38123812
hbs.registerHelper("ne", dom::makeVariadicInvocable(ne_fn));
38133813
hbs.registerHelper("not", dom::makeVariadicInvocable(not_fn));
38143814
hbs.registerHelper("or", dom::makeVariadicInvocable(or_fn));
3815-
hbs.registerHelper("relativize", dom::makeInvocable(relativize_fn));
38163815
hbs.registerHelper("year", dom::makeInvocable(year_fn));
38173816
}
38183817

@@ -3948,89 +3947,6 @@ detag_fn(dom::Value html)
39483947
return result;
39493948
}
39503949

3951-
dom::Value
3952-
relativize_fn(dom::Value to, dom::Value from, dom::Value context)
3953-
{
3954-
// https://gitlab.com/antora/antora-ui-default/-/blob/master/src/helpers/relativize.js
3955-
if (!to)
3956-
{
3957-
return "#";
3958-
}
3959-
3960-
if (to.isString() && !std::string_view(to.getString()).starts_with('/'))
3961-
{
3962-
return to;
3963-
}
3964-
3965-
if (!context)
3966-
{
3967-
// NOTE only legacy invocation provides both to and from
3968-
context = from;
3969-
from = context.lookup("data.root.page.url");
3970-
}
3971-
3972-
if (!from)
3973-
{
3974-
dom::Value sitePath = context.lookup("data.root.site.path");
3975-
if (sitePath)
3976-
{
3977-
return sitePath + to;
3978-
}
3979-
return to;
3980-
}
3981-
3982-
dom::Value hash = "";
3983-
std::size_t hashIdx = to.getString().get().find('#');
3984-
if (hashIdx != std::string_view::npos)
3985-
{
3986-
hash = to.getString().get().substr(hashIdx);
3987-
to = to.getString().get().substr(0, hashIdx);
3988-
}
3989-
3990-
/// return to === from
3991-
// ? hash || (isDir(to) ? './' : path.basename(to))
3992-
// : (path.relative(path.dirname(from + '.'), to) || '.') + (isDir(to) ? '/' + hash : hash)
3993-
if (to == from)
3994-
{
3995-
if (hash) {
3996-
return hash;
3997-
}
3998-
else if (to.isString() && files::isDirsy(to.getString().get()))
3999-
{
4000-
return "./";
4001-
}
4002-
else if (to.isString())
4003-
{
4004-
return files::getFileName(to.getString().get());
4005-
}
4006-
else
4007-
{
4008-
return to;
4009-
}
4010-
}
4011-
else
4012-
{
4013-
// AFREITAS: Implement this functionality without std::filesystem
4014-
if (!to.isString() || !from.isString()) {
4015-
return to;
4016-
}
4017-
std::string relativePath = std::filesystem::relative(
4018-
std::filesystem::path(std::string_view(to.getString())),
4019-
std::filesystem::path(std::string_view(from.getString()))).generic_string();
4020-
if (relativePath.empty())
4021-
{
4022-
relativePath = ".";
4023-
}
4024-
if (files::isDirsy(to.getString())) {
4025-
return relativePath + '/' + hash;
4026-
}
4027-
else
4028-
{
4029-
return relativePath + hash;
4030-
}
4031-
}
4032-
}
4033-
40343950
int
40353951
year_fn() {
40363952
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();

0 commit comments

Comments
 (0)