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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
#include "link.h"
#include "name.h"
#include <yql/essentials/utils/yql_panic.h>
#include <contrib/libs/re2/re2/re2.h>
#include <util/string/builder.h>
#include <util/string/split.h>
namespace NYql::NDocs {
TLinkTarget TLinkTarget::Parse(TStringBuf string) {
static const RE2 Regex(R"re(([^#?()]*)(#[^?()]*)?)re");
TString path;
TString anchor;
if (RE2::FullMatch(string, Regex, &path, &anchor)) {
if (!anchor.empty()) {
YQL_ENSURE(anchor.StartsWith('#'));
anchor.erase(0, 1);
}
return {
.RelativePath = path,
.Anchor = !anchor.empty() ? TMaybe<TString>(anchor) : Nothing(),
};
}
throw yexception()
<< "invalid link target '" << string << "': "
<< "does not match regex '" << Regex.pattern() << "'";
}
TMaybe<TLinkTarget> LookupUDF(const TLinks& links, TStringBuf name) {
const auto udf = SplitUDF(TString(name));
YQL_ENSURE(udf, "Invalid UDF: " << name);
const auto [module, function] = *udf;
if (const TLinkTarget* target = nullptr;
(target = links.FindPtr(module + "::" + function)) ||
(target = links.FindPtr(module + "::" + "*"))) {
return *target;
}
return Nothing();
}
TMaybe<TLinkTarget> LookupBasic(const TLinks& links, TStringBuf name) {
TMaybe<TLinkKey> key = NormalizedName(TString(name));
if (!key) {
return Nothing();
}
if (const TLinkTarget* target = links.FindPtr(*key)) {
return *target;
}
return Nothing();
}
TMaybe<TLinkTarget> Lookup(const TLinks& links, TStringBuf name) {
if (IsUDF(name)) {
return LookupUDF(links, name);
}
return LookupBasic(links, name);
}
TLinkKey ParseLinkKey(TStringBuf string) {
static RE2 UDFRegex(TStringBuilder()
<< "(" << NormalizedNameRegex.pattern() << ")\\:\\:("
<< "\\*|" << NormalizedNameRegex.pattern() << ")");
if (IsNormalizedName(string)) {
return TString(string);
}
if (RE2::FullMatch(string, UDFRegex)) {
return TString(string);
}
ythrow yexception()
<< "invalid link key '" << string << "': "
<< "does not match any regex";
}
TLinks ParseLinks(const NJson::TJsonValue& json) {
TLinks links;
for (const auto& [keyString, value] : json.GetMapSafe()) {
TLinkKey key = ParseLinkKey(keyString);
TLinkTarget target = TLinkTarget::Parse(value.GetStringSafe());
links[std::move(key)] = std::move(target);
}
return links;
}
TLinks Merge(TLinks&& lhs, TLinks&& rhs) {
for (auto& [k, v] : rhs) {
YQL_ENSURE(
!lhs.contains(k),
"Duplicate '" << k << "', old '" << lhs[k] << "', new '" << v << "'");
lhs[k] = std::move(v);
}
return lhs;
}
} // namespace NYql::NDocs
template <>
void Out<NYql::NDocs::TLinkTarget>(IOutputStream& out, const NYql::NDocs::TLinkTarget& target) {
out << target.RelativePath;
if (target.Anchor) {
out << "#" << *target.Anchor;
}
}
|