diff options
author | vvvv <[email protected]> | 2025-10-06 11:26:09 +0300 |
---|---|---|
committer | vvvv <[email protected]> | 2025-10-06 11:53:26 +0300 |
commit | 60f45e69a4d7dbc6131208e16c45faf35aa5a985 (patch) | |
tree | 4daa45b52c295a178c7620e4c93921465fcf7950 /yql/essentials/utils/docs | |
parent | 1bded1a65a7e6e9171418f3e1c691d390125b64e (diff) |
YQL-20086 utils
init
commit_hash:54feccd520ebd0ab23612bc0cb830914dff9d0e8
Diffstat (limited to 'yql/essentials/utils/docs')
-rw-r--r-- | yql/essentials/utils/docs/link.cpp | 142 | ||||
-rw-r--r-- | yql/essentials/utils/docs/link.h | 22 | ||||
-rw-r--r-- | yql/essentials/utils/docs/link_page.cpp | 168 | ||||
-rw-r--r-- | yql/essentials/utils/docs/link_page.h | 4 | ||||
-rw-r--r-- | yql/essentials/utils/docs/markdown.cpp | 190 | ||||
-rw-r--r-- | yql/essentials/utils/docs/markdown.h | 28 | ||||
-rw-r--r-- | yql/essentials/utils/docs/markdown_ut.cpp | 72 | ||||
-rw-r--r-- | yql/essentials/utils/docs/name.cpp | 56 | ||||
-rw-r--r-- | yql/essentials/utils/docs/name.h | 10 | ||||
-rw-r--r-- | yql/essentials/utils/docs/page.cpp | 102 | ||||
-rw-r--r-- | yql/essentials/utils/docs/page.h | 8 | ||||
-rw-r--r-- | yql/essentials/utils/docs/page_ut.cpp | 46 | ||||
-rw-r--r-- | yql/essentials/utils/docs/resource.cpp | 60 | ||||
-rw-r--r-- | yql/essentials/utils/docs/resource.h | 14 | ||||
-rw-r--r-- | yql/essentials/utils/docs/ut/ya.make | 2 | ||||
-rw-r--r-- | yql/essentials/utils/docs/verification.cpp | 178 | ||||
-rw-r--r-- | yql/essentials/utils/docs/verification.h | 32 | ||||
-rw-r--r-- | yql/essentials/utils/docs/ya.make | 2 |
18 files changed, 570 insertions, 566 deletions
diff --git a/yql/essentials/utils/docs/link.cpp b/yql/essentials/utils/docs/link.cpp index 2fd5321ff12..af3d648db9e 100644 --- a/yql/essentials/utils/docs/link.cpp +++ b/yql/essentials/utils/docs/link.cpp @@ -11,102 +11,102 @@ 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(), - }; +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); } - throw yexception() - << "invalid link target '" << string << "': " - << "does not match regex '" << Regex.pattern() << "'"; + return { + .RelativePath = path, + .Anchor = !anchor.empty() ? TMaybe<TString>(anchor) : Nothing(), + }; } - TMaybe<TLinkTarget> LookupUDF(const TLinks& links, TStringBuf name) { - const auto udf = SplitUDF(TString(name)); - YQL_ENSURE(udf, "Invalid UDF: " << name); + throw yexception() + << "invalid link target '" << string << "': " + << "does not match regex '" << Regex.pattern() << "'"; +} - const auto [module, function] = *udf; +TMaybe<TLinkTarget> LookupUDF(const TLinks& links, TStringBuf name) { + const auto udf = SplitUDF(TString(name)); + YQL_ENSURE(udf, "Invalid UDF: " << name); - if (const TLinkTarget* target = nullptr; - (target = links.FindPtr(module + "::" + function)) || - (target = links.FindPtr(module + "::" + "*"))) { - return *target; - } + const auto [module, function] = *udf; - return Nothing(); + if (const TLinkTarget* target = nullptr; + (target = links.FindPtr(module + "::" + function)) || + (target = links.FindPtr(module + "::" + "*"))) { + return *target; } - 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> LookupBasic(const TLinks& links, TStringBuf name) { + TMaybe<TLinkKey> key = NormalizedName(TString(name)); + if (!key) { return Nothing(); } - TMaybe<TLinkTarget> Lookup(const TLinks& links, TStringBuf name) { - if (IsUDF(name)) { - return LookupUDF(links, name); - } + if (const TLinkTarget* target = links.FindPtr(*key)) { + return *target; + } + + return Nothing(); +} - return LookupBasic(links, name); +TMaybe<TLinkTarget> Lookup(const TLinks& links, TStringBuf name) { + if (IsUDF(name)) { + return LookupUDF(links, name); } - TLinkKey ParseLinkKey(TStringBuf string) { - static RE2 UDFRegex(TStringBuilder() - << "(" << NormalizedNameRegex.pattern() << ")\\:\\:(" - << "\\*|" << NormalizedNameRegex.pattern() << ")"); + return LookupBasic(links, name); +} - if (IsNormalizedName(string)) { - return TString(string); - } +TLinkKey ParseLinkKey(TStringBuf string) { + static RE2 UDFRegex(TStringBuilder() + << "(" << NormalizedNameRegex.pattern() << ")\\:\\:(" + << "\\*|" << NormalizedNameRegex.pattern() << ")"); - if (RE2::FullMatch(string, UDFRegex)) { - return TString(string); - } + if (IsNormalizedName(string)) { + return TString(string); + } - ythrow yexception() - << "invalid link key '" << string << "': " - << "does not match any regex"; + if (RE2::FullMatch(string, UDFRegex)) { + return TString(string); } - 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; + 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 << "'"); +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; + lhs[k] = std::move(v); } + return lhs; +} } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/link.h b/yql/essentials/utils/docs/link.h index 961f460b99a..70e91d99a27 100644 --- a/yql/essentials/utils/docs/link.h +++ b/yql/essentials/utils/docs/link.h @@ -7,23 +7,23 @@ namespace NYql::NDocs { - struct TLinkTarget { - TString RelativePath; - TMaybe<TString> Anchor; +struct TLinkTarget { + TString RelativePath; + TMaybe<TString> Anchor; - static TLinkTarget Parse(TStringBuf string); - }; + static TLinkTarget Parse(TStringBuf string); +}; - using TLinkKey = TString; +using TLinkKey = TString; - using TLinks = THashMap<TLinkKey, TLinkTarget>; +using TLinks = THashMap<TLinkKey, TLinkTarget>; - TMaybe<TLinkTarget> Lookup(const TLinks& links, TStringBuf name); +TMaybe<TLinkTarget> Lookup(const TLinks& links, TStringBuf name); - TLinkKey ParseLinkKey(TStringBuf string); +TLinkKey ParseLinkKey(TStringBuf string); - TLinks ParseLinks(const NJson::TJsonValue& json); +TLinks ParseLinks(const NJson::TJsonValue& json); - TLinks Merge(TLinks&& lhs, TLinks&& rhs); +TLinks Merge(TLinks&& lhs, TLinks&& rhs); } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/link_page.cpp b/yql/essentials/utils/docs/link_page.cpp index eb71979462d..985410fafd5 100644 --- a/yql/essentials/utils/docs/link_page.cpp +++ b/yql/essentials/utils/docs/link_page.cpp @@ -7,110 +7,110 @@ namespace NYql::NDocs { - TMaybe<TString> MatchSingleFunctionHeader(TStringBuf header) { - return NormalizedName(TString(header)); +TMaybe<TString> MatchSingleFunctionHeader(TStringBuf header) { + return NormalizedName(TString(header)); +} + +TVector<TString> SplitBy(TStringBuf delim, const TVector<TString>& strings) { + TVector<TString> parts; + for (const TString& s : strings) { + StringSplitter(s).SplitByString(delim).AddTo(&parts); } - - TVector<TString> SplitBy(TStringBuf delim, const TVector<TString>& strings) { - TVector<TString> parts; - for (const TString& s : strings) { - StringSplitter(s).SplitByString(delim).AddTo(&parts); + return parts; +} + +TVector<TString> SplitByPunctuation(TStringBuf header) { + TVector<TString> parts = {TString(header)}; + parts = SplitBy(" и ", parts); + parts = SplitBy(" / ", parts); + parts = SplitBy(", ", parts); + return parts; +} + +TVector<TString> MatchMultiFunctionHeader(TStringBuf header) { + TVector<TString> names = SplitByPunctuation(header); + + for (TString& name : names) { + TMaybe<TString> normalized = NormalizedName(std::move(name)); + if (!normalized) { + return {}; } - return parts; - } - TVector<TString> SplitByPunctuation(TStringBuf header) { - TVector<TString> parts = {TString(header)}; - parts = SplitBy(" и ", parts); - parts = SplitBy(" / ", parts); - parts = SplitBy(", ", parts); - return parts; + name = std::move(*normalized); } - TVector<TString> MatchMultiFunctionHeader(TStringBuf header) { - TVector<TString> names = SplitByPunctuation(header); - - for (TString& name : names) { - TMaybe<TString> normalized = NormalizedName(std::move(name)); - if (!normalized) { - return {}; - } - - name = std::move(*normalized); - } + return names; +} - return names; +TVector<TString> ExtractNormalized(TStringBuf header) { + if (auto single = MatchSingleFunctionHeader(header)) { + return {*single}; } - - TVector<TString> ExtractNormalized(TStringBuf header) { - if (auto single = MatchSingleFunctionHeader(header)) { - return {*single}; - } - if (auto multi = MatchMultiFunctionHeader(header)) { - return multi; - } - return {}; + if (auto multi = MatchMultiFunctionHeader(header)) { + return multi; } - - void EnrichFromMarkdown(TLinks& links, const TString& path, const TMarkdownHeader& header) { - for (const TString& name : ExtractNormalized(header.Content)) { - links[name] = { - .RelativePath = path, - .Anchor = header.Anchor, - }; - } + return {}; +} + +void EnrichFromMarkdown(TLinks& links, const TString& path, const TMarkdownHeader& header) { + for (const TString& name : ExtractNormalized(header.Content)) { + links[name] = { + .RelativePath = path, + .Anchor = header.Anchor, + }; } +} - void EnrichFromMarkdown(TLinks& links, const TString& path, const TMarkdownPage& page) { - for (const auto& [anchor, section] : page.SectionsByAnchor) { - const TMarkdownHeader& header = section.Header; - EnrichFromMarkdown(links, path, header); - } +void EnrichFromMarkdown(TLinks& links, const TString& path, const TMarkdownPage& page) { + for (const auto& [anchor, section] : page.SectionsByAnchor) { + const TMarkdownHeader& header = section.Header; + EnrichFromMarkdown(links, path, header); } +} - void EnrichFromMarkdown(TLinks& links, const TPages& pages) { - for (const auto& [path, page] : pages) { - EnrichFromMarkdown(links, path, page); - } +void EnrichFromMarkdown(TLinks& links, const TPages& pages) { + for (const auto& [path, page] : pages) { + EnrichFromMarkdown(links, path, page); } - - TLinks GetLinksFromPages(const TPages& pages) { - TLinks links; - EnrichFromMarkdown(links, pages); - return links; +} + +TLinks GetLinksFromPages(const TPages& pages) { + TLinks links; + EnrichFromMarkdown(links, pages); + return links; +} + +TPages Stripped(TPages&& pages, const TLinks& links) { + THashSet<TString> usedPaths; + THashMap<TString, THashSet<TString>> usedAnchors; + for (const auto& [_, link] : links) { + TString anchor = link.Anchor.GetOrElse(""); + usedAnchors[link.RelativePath].emplace(std::move(anchor)); } - TPages Stripped(TPages&& pages, const TLinks& links) { - THashSet<TString> usedPaths; - THashMap<TString, THashSet<TString>> usedAnchors; - for (const auto& [_, link] : links) { - TString anchor = link.Anchor.GetOrElse(""); - usedAnchors[link.RelativePath].emplace(std::move(anchor)); - } - - THashSet<TString> unusedPaths; - THashMap<TString, THashSet<TString>> unusedAnchors; - for (const auto& [path, page] : pages) { - for (const auto& [anchor, _] : page.SectionsByAnchor) { - if (!usedAnchors.contains(path)) { - unusedPaths.emplace(path); - } else if (!usedAnchors[path].contains(anchor)) { - unusedAnchors[path].emplace(anchor); - } - } - } - - for (const auto& [path, anchors] : unusedAnchors) { - for (const auto& anchor : anchors) { - pages[path].SectionsByAnchor.erase(anchor); + THashSet<TString> unusedPaths; + THashMap<TString, THashSet<TString>> unusedAnchors; + for (const auto& [path, page] : pages) { + for (const auto& [anchor, _] : page.SectionsByAnchor) { + if (!usedAnchors.contains(path)) { + unusedPaths.emplace(path); + } else if (!usedAnchors[path].contains(anchor)) { + unusedAnchors[path].emplace(anchor); } } + } - for (const auto& path : unusedPaths) { - pages.erase(path); + for (const auto& [path, anchors] : unusedAnchors) { + for (const auto& anchor : anchors) { + pages[path].SectionsByAnchor.erase(anchor); } + } - return pages; + for (const auto& path : unusedPaths) { + pages.erase(path); } + return pages; +} + } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/link_page.h b/yql/essentials/utils/docs/link_page.h index beeb1252ef2..532da3fc539 100644 --- a/yql/essentials/utils/docs/link_page.h +++ b/yql/essentials/utils/docs/link_page.h @@ -5,8 +5,8 @@ namespace NYql::NDocs { - TLinks GetLinksFromPages(const TPages& pages); +TLinks GetLinksFromPages(const TPages& pages); - TPages Stripped(TPages&& pages, const TLinks& links); +TPages Stripped(TPages&& pages, const TLinks& links); } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/markdown.cpp b/yql/essentials/utils/docs/markdown.cpp index fd13820b8c4..fb4209717e4 100644 --- a/yql/essentials/utils/docs/markdown.cpp +++ b/yql/essentials/utils/docs/markdown.cpp @@ -9,127 +9,127 @@ namespace NYql::NDocs { - class TMarkdownParser { - private: - static constexpr TStringBuf HeaderRegex = R"re(([^#]+)(\s+{#([a-z0-9\-_]+)})?)re"; - - public: - explicit TMarkdownParser(size_t headerDepth) - : HeaderDepth_(headerDepth) - , SectionHeaderRegex_(" *" + TString(HeaderDepth_, '#') + " " + HeaderRegex) - , IsSkipping_(true) - { - } +class TMarkdownParser { +private: + static constexpr TStringBuf HeaderRegex = R"re(([^#]+)(\s+{#([a-z0-9\-_]+)})?)re"; + +public: + explicit TMarkdownParser(size_t headerDepth) + : HeaderDepth_(headerDepth) + , SectionHeaderRegex_(" *" + TString(HeaderDepth_, '#') + " " + HeaderRegex) + , IsSkipping_(true) + { + } - void Parse(IInputStream& markdown, TMarkdownCallback&& onSection) { - for (TString line; markdown.ReadLine(line) != 0;) { - size_t depth = HeaderDepth(line); - if (IsSkipping_) { - if (HeaderDepth_ == depth) { - ResetSection(std::move(line)); - IsSkipping_ = false; - } else { - // Skip - } + void Parse(IInputStream& markdown, TMarkdownCallback&& onSection) { + for (TString line; markdown.ReadLine(line) != 0;) { + size_t depth = HeaderDepth(line); + if (IsSkipping_) { + if (HeaderDepth_ == depth) { + ResetSection(std::move(line)); + IsSkipping_ = false; } else { - if (HeaderDepth_ == depth) { - onSection(std::move(Section_)); - ResetSection(std::move(line)); - } else if (depth == 0 || HeaderDepth_ < depth) { - line.append('\n'); - Section_.Body.append(std::move(line)); - } else { - onSection(std::move(Section_)); - IsSkipping_ = true; - } + // Skip + } + } else { + if (HeaderDepth_ == depth) { + onSection(std::move(Section_)); + ResetSection(std::move(line)); + } else if (depth == 0 || HeaderDepth_ < depth) { + line.append('\n'); + Section_.Body.append(std::move(line)); + } else { + onSection(std::move(Section_)); + IsSkipping_ = true; } - } - - if (!IsSkipping_) { - onSection(std::move(Section_)); } } - private: - void ResetSection(TString&& line) { - Section_ = TMarkdownSection(); + if (!IsSkipping_) { + onSection(std::move(Section_)); + } + } - TString content; - std::optional<TString> dummy; - std::optional<TString> anchor; - if (!RE2::FullMatch(line, SectionHeaderRegex_, &content, &dummy, &anchor)) { - Section_.Header.Content = std::move(line); - return; - } +private: + void ResetSection(TString&& line) { + Section_ = TMarkdownSection(); - Section_.Header.Content = std::move(content); - if (anchor) { - Section_.Header.Anchor = std::move(*anchor); - } + TString content; + std::optional<TString> dummy; + std::optional<TString> anchor; + if (!RE2::FullMatch(line, SectionHeaderRegex_, &content, &dummy, &anchor)) { + Section_.Header.Content = std::move(line); + return; } - size_t HeaderDepth(TStringBuf line) const { - while (line.StartsWith(' ') || line.StartsWith('\t')) { - line.Skip(1); - } + Section_.Header.Content = std::move(content); + if (anchor) { + Section_.Header.Anchor = std::move(*anchor); + } + } - if (!line.StartsWith('#')) { - return 0; - } + size_t HeaderDepth(TStringBuf line) const { + while (line.StartsWith(' ') || line.StartsWith('\t')) { + line.Skip(1); + } - size_t begin = line.find('#'); - size_t end = line.find_first_not_of('#', begin); - return end != TStringBuf::npos ? (end - begin) : 0; + if (!line.StartsWith('#')) { + return 0; } - size_t HeaderDepth_; - RE2 SectionHeaderRegex_; - bool IsSkipping_; - TMarkdownSection Section_; - }; + size_t begin = line.find('#'); + size_t end = line.find_first_not_of('#', begin); + return end != TStringBuf::npos ? (end - begin) : 0; + } - TMaybe<TString> Anchor(const TMarkdownHeader& header) { - static RE2 Regex(R"re([0-9a-z\-_]+)re"); + size_t HeaderDepth_; + RE2 SectionHeaderRegex_; + bool IsSkipping_; + TMarkdownSection Section_; +}; - if (header.Anchor) { - return header.Anchor; - } +TMaybe<TString> Anchor(const TMarkdownHeader& header) { + static RE2 Regex(R"re([0-9a-z\-_]+)re"); - TString content = ToLowerUTF8(header.Content); - SubstGlobal(content, ' ', '-'); + if (header.Anchor) { + return header.Anchor; + } - if (RE2::FullMatch(content, Regex)) { - return content; - } + TString content = ToLowerUTF8(header.Content); + SubstGlobal(content, ' ', '-'); - return Nothing(); + if (RE2::FullMatch(content, Regex)) { + return content; } - TMarkdownPage ParseMarkdownPage(TString markdown) { - TMarkdownPage page; + return Nothing(); +} - const auto onSection = [&](TMarkdownSection&& section) { - if (TMaybe<TString> anchor = Anchor(section.Header)) { - section.Header.Anchor = anchor; - page.SectionsByAnchor[*anchor] = std::move(section); - } - }; +TMarkdownPage ParseMarkdownPage(TString markdown) { + TMarkdownPage page; - { - TMarkdownParser parser(/*headerDepth=*/2); - TStringStream stream(markdown); - parser.Parse(stream, onSection); - } - - { - TMarkdownParser parser(/*headerDepth=*/3); - TStringStream stream(markdown); - parser.Parse(stream, onSection); + const auto onSection = [&](TMarkdownSection&& section) { + if (TMaybe<TString> anchor = Anchor(section.Header)) { + section.Header.Anchor = anchor; + page.SectionsByAnchor[*anchor] = std::move(section); } + }; - page.Text = std::move(markdown); + { + TMarkdownParser parser(/*headerDepth=*/2); + TStringStream stream(markdown); + parser.Parse(stream, onSection); + } - return page; + { + TMarkdownParser parser(/*headerDepth=*/3); + TStringStream stream(markdown); + parser.Parse(stream, onSection); } + page.Text = std::move(markdown); + + return page; +} + } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/markdown.h b/yql/essentials/utils/docs/markdown.h index 6b5477ac253..ebc9707f52a 100644 --- a/yql/essentials/utils/docs/markdown.h +++ b/yql/essentials/utils/docs/markdown.h @@ -7,23 +7,23 @@ namespace NYql::NDocs { - struct TMarkdownHeader { - TString Content; - TMaybe<TString> Anchor; - }; +struct TMarkdownHeader { + TString Content; + TMaybe<TString> Anchor; +}; - struct TMarkdownSection { - TMarkdownHeader Header; - TString Body; - }; +struct TMarkdownSection { + TMarkdownHeader Header; + TString Body; +}; - struct TMarkdownPage { - TString Text; - THashMap<TString, TMarkdownSection> SectionsByAnchor; - }; +struct TMarkdownPage { + TString Text; + THashMap<TString, TMarkdownSection> SectionsByAnchor; +}; - using TMarkdownCallback = std::function<void(TMarkdownSection&&)>; +using TMarkdownCallback = std::function<void(TMarkdownSection&&)>; - TMarkdownPage ParseMarkdownPage(TString markdown); +TMarkdownPage ParseMarkdownPage(TString markdown); } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/markdown_ut.cpp b/yql/essentials/utils/docs/markdown_ut.cpp index 45e45e645a5..7aee0e3deac 100644 --- a/yql/essentials/utils/docs/markdown_ut.cpp +++ b/yql/essentials/utils/docs/markdown_ut.cpp @@ -6,8 +6,8 @@ using namespace NYql::NDocs; Y_UNIT_TEST_SUITE(MarkdownParserTests) { - Y_UNIT_TEST(ParseMarkdown) { - TString markdown = R"( +Y_UNIT_TEST(ParseMarkdown) { + TString markdown = R"( # Basic built-in functions Below are the general-purpose functions. @@ -51,27 +51,27 @@ SELECT FROM my_table; ``` )"; - TMarkdownPage page = ParseMarkdownPage(markdown); - - UNIT_ASSERT_VALUES_EQUAL(page.SectionsByAnchor.size(), 2); - - const auto& coelcese = page.SectionsByAnchor["coalesce"]; - UNIT_ASSERT_STRING_CONTAINS(coelcese.Header.Content, "COALESCE"); - UNIT_ASSERT_VALUES_EQUAL(coelcese.Header.Anchor, "coalesce"); - UNIT_ASSERT_STRING_CONTAINS(coelcese.Body, "Iterates"); - UNIT_ASSERT_STRING_CONTAINS(coelcese.Body, "COALESCE"); - UNIT_ASSERT_GE(Count(coelcese.Body, '\n'), 5); - - const auto& random = page.SectionsByAnchor["random"]; - UNIT_ASSERT_STRING_CONTAINS(random.Header.Content, "Random"); - UNIT_ASSERT_VALUES_EQUAL(random.Header.Anchor, "random"); - UNIT_ASSERT_STRING_CONTAINS(random.Body, "Generates"); - UNIT_ASSERT_STRING_CONTAINS(random.Body, "Random"); - UNIT_ASSERT_GE(Count(random.Body, '\n'), 5); - } - - Y_UNIT_TEST(NestedSections) { - TString markdown = R"( + TMarkdownPage page = ParseMarkdownPage(markdown); + + UNIT_ASSERT_VALUES_EQUAL(page.SectionsByAnchor.size(), 2); + + const auto& coelcese = page.SectionsByAnchor["coalesce"]; + UNIT_ASSERT_STRING_CONTAINS(coelcese.Header.Content, "COALESCE"); + UNIT_ASSERT_VALUES_EQUAL(coelcese.Header.Anchor, "coalesce"); + UNIT_ASSERT_STRING_CONTAINS(coelcese.Body, "Iterates"); + UNIT_ASSERT_STRING_CONTAINS(coelcese.Body, "COALESCE"); + UNIT_ASSERT_GE(Count(coelcese.Body, '\n'), 5); + + const auto& random = page.SectionsByAnchor["random"]; + UNIT_ASSERT_STRING_CONTAINS(random.Header.Content, "Random"); + UNIT_ASSERT_VALUES_EQUAL(random.Header.Anchor, "random"); + UNIT_ASSERT_STRING_CONTAINS(random.Body, "Generates"); + UNIT_ASSERT_STRING_CONTAINS(random.Body, "Random"); + UNIT_ASSERT_GE(Count(random.Body, '\n'), 5); +} + +Y_UNIT_TEST(NestedSections) { + TString markdown = R"( # Section 1 {#s1} Section 1 Text. ## Subsection 1 {#s1s1} @@ -89,19 +89,19 @@ Subsection 2.2.1 Text. # Section 3 {#s3} Section 3 Text. )"; - TMarkdownPage page = ParseMarkdownPage(markdown); - { - const TMarkdownSection& section = page.SectionsByAnchor["s1s2"]; - UNIT_ASSERT_STRING_CONTAINS(section.Body, "Subsection 1.2 Text."); - UNIT_ASSERT_C(!section.Body.Contains("Section 1 Text."), section.Body); - UNIT_ASSERT_C(!section.Body.Contains("Section 2 Text."), section.Body); - UNIT_ASSERT_C(!section.Body.Contains("Section 3 Text."), section.Body); - } - { - const TMarkdownSection& section = page.SectionsByAnchor["s2s2s1"]; - UNIT_ASSERT_STRING_CONTAINS(section.Body, "Subsection 2.2.1 Text."); - UNIT_ASSERT_C(!section.Body.Contains("Section 3 Text."), section.Body); - } + TMarkdownPage page = ParseMarkdownPage(markdown); + { + const TMarkdownSection& section = page.SectionsByAnchor["s1s2"]; + UNIT_ASSERT_STRING_CONTAINS(section.Body, "Subsection 1.2 Text."); + UNIT_ASSERT_C(!section.Body.Contains("Section 1 Text."), section.Body); + UNIT_ASSERT_C(!section.Body.Contains("Section 2 Text."), section.Body); + UNIT_ASSERT_C(!section.Body.Contains("Section 3 Text."), section.Body); + } + { + const TMarkdownSection& section = page.SectionsByAnchor["s2s2s1"]; + UNIT_ASSERT_STRING_CONTAINS(section.Body, "Subsection 2.2.1 Text."); + UNIT_ASSERT_C(!section.Body.Contains("Section 3 Text."), section.Body); } +} } // Y_UNIT_TEST_SUITE(MarkdownParserTests) diff --git a/yql/essentials/utils/docs/name.cpp b/yql/essentials/utils/docs/name.cpp index 570bf23f313..9ebf04d06bd 100644 --- a/yql/essentials/utils/docs/name.cpp +++ b/yql/essentials/utils/docs/name.cpp @@ -7,43 +7,43 @@ namespace NYql::NDocs { - const RE2 NormalizedNameRegex(R"re([a-z_]{1,2}[a-z0-9]*)re"); +const RE2 NormalizedNameRegex(R"re([a-z_]{1,2}[a-z0-9]*)re"); - bool IsNormalizedName(TStringBuf name) { - return RE2::FullMatch(name, NormalizedNameRegex); +bool IsNormalizedName(TStringBuf name) { + return RE2::FullMatch(name, NormalizedNameRegex); +} + +TMaybe<TString> NormalizedName(TString name) { + if (TMaybe<TIssue> issue = NormalizeName(TPosition(), name)) { + return Nothing(); } - TMaybe<TString> NormalizedName(TString name) { - if (TMaybe<TIssue> issue = NormalizeName(TPosition(), name)) { - return Nothing(); - } + if (!IsNormalizedName(name)) { + return Nothing(); + } - if (!IsNormalizedName(name)) { - return Nothing(); - } + return name; +} - return name; - } +bool IsUDF(TStringBuf name) { + return name.Contains("::"); +} - bool IsUDF(TStringBuf name) { - return name.Contains("::"); +TMaybe<std::pair<TString, TString>> SplitUDF(TString name) { + if (!IsUDF(name)) { + return Nothing(); } - TMaybe<std::pair<TString, TString>> SplitUDF(TString name) { - if (!IsUDF(name)) { - return Nothing(); - } + TVector<TString> words; + words.reserve(2); + StringSplitter(name).SplitByString("::").Collect(&words); + YQL_ENSURE(words.size() == 2, "Invalid UDF pattern: " << name); - TVector<TString> words; - words.reserve(2); - StringSplitter(name).SplitByString("::").Collect(&words); - YQL_ENSURE(words.size() == 2, "Invalid UDF pattern: " << name); + TMaybe<TString> module = NormalizedName(std::move(words[0])); + TMaybe<TString> function = NormalizedName(std::move(words[1])); + YQL_ENSURE(module && function, "Unable to normalize " << name); - TMaybe<TString> module = NormalizedName(std::move(words[0])); - TMaybe<TString> function = NormalizedName(std::move(words[1])); - YQL_ENSURE(module && function, "Unable to normalize " << name); - - return std::make_pair(*module, *function); - } + return std::make_pair(*module, *function); +} } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/name.h b/yql/essentials/utils/docs/name.h index 3ab303ca23f..0328801b76b 100644 --- a/yql/essentials/utils/docs/name.h +++ b/yql/essentials/utils/docs/name.h @@ -6,14 +6,14 @@ namespace NYql::NDocs { - extern const RE2 NormalizedNameRegex; +extern const RE2 NormalizedNameRegex; - bool IsNormalizedName(TStringBuf name); +bool IsNormalizedName(TStringBuf name); - TMaybe<TString> NormalizedName(TString name); +TMaybe<TString> NormalizedName(TString name); - bool IsUDF(TStringBuf name); +bool IsUDF(TStringBuf name); - TMaybe<std::pair<TString, TString>> SplitUDF(TString name); +TMaybe<std::pair<TString, TString>> SplitUDF(TString name); } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/page.cpp b/yql/essentials/utils/docs/page.cpp index 516b8b2886e..f0b1671a9dd 100644 --- a/yql/essentials/utils/docs/page.cpp +++ b/yql/essentials/utils/docs/page.cpp @@ -6,71 +6,71 @@ namespace NYql::NDocs { - TString ResolvedMarkdownText(TStringBuf relativePath, TString text, TStringBuf baseURL) { - static const RE2 anchorRegex(R"re(\[([^\\\]]+)\]\((#[^\\)]+)\))re"); - static const RE2 linkRegex(R"re(\[([^\\\]]+)\]\(([A-Za-z0-9/_\-\.]+).md(#[^\\)]+)?\))re"); +TString ResolvedMarkdownText(TStringBuf relativePath, TString text, TStringBuf baseURL) { + static const RE2 anchorRegex(R"re(\[([^\\\]]+)\]\((#[^\\)]+)\))re"); + static const RE2 linkRegex(R"re(\[([^\\\]]+)\]\(([A-Za-z0-9/_\-\.]+).md(#[^\\)]+)?\))re"); - TString base = TString(baseURL) + "/" + TString(relativePath); - TString anchorRewrite = "[\\1](" + base + "\\2)"; - TString linkRewrite = "[\\1](" + base + "/../" + "\\2\\3)"; + TString base = TString(baseURL) + "/" + TString(relativePath); + TString anchorRewrite = "[\\1](" + base + "\\2)"; + TString linkRewrite = "[\\1](" + base + "/../" + "\\2\\3)"; - TString error; - YQL_ENSURE( - anchorRegex.CheckRewriteString(anchorRewrite, &error), - "Bad rewrite '" << anchorRewrite << "': " << error); - YQL_ENSURE( - linkRegex.CheckRewriteString(linkRewrite, &error), - "Bad rewrite '" << linkRewrite << "': " << error); + TString error; + YQL_ENSURE( + anchorRegex.CheckRewriteString(anchorRewrite, &error), + "Bad rewrite '" << anchorRewrite << "': " << error); + YQL_ENSURE( + linkRegex.CheckRewriteString(linkRewrite, &error), + "Bad rewrite '" << linkRewrite << "': " << error); - RE2::GlobalReplace(&text, anchorRegex, anchorRewrite); - RE2::GlobalReplace(&text, linkRegex, linkRewrite); + RE2::GlobalReplace(&text, anchorRegex, anchorRewrite); + RE2::GlobalReplace(&text, linkRegex, linkRewrite); - return text; - } + return text; +} - TMarkdownPage Resolved(TStringBuf relativePath, TMarkdownPage page, TStringBuf baseURL) { - page.Text = ResolvedMarkdownText(relativePath, page.Text, baseURL); - for (auto& [_, section] : page.SectionsByAnchor) { - section.Body = ResolvedMarkdownText(relativePath, std::move(section.Body), baseURL); - } - return page; +TMarkdownPage Resolved(TStringBuf relativePath, TMarkdownPage page, TStringBuf baseURL) { + page.Text = ResolvedMarkdownText(relativePath, page.Text, baseURL); + for (auto& [_, section] : page.SectionsByAnchor) { + section.Body = ResolvedMarkdownText(relativePath, std::move(section.Body), baseURL); } + return page; +} - TString ExtendedSyntaxRemoved(TString text) { - static const RE2 regex(R"re( *{%[^\\]*?%} *\n?)re"); - RE2::GlobalReplace(&text, regex, ""); - return text; - } +TString ExtendedSyntaxRemoved(TString text) { + static const RE2 regex(R"re( *{%[^\\]*?%} *\n?)re"); + RE2::GlobalReplace(&text, regex, ""); + return text; +} - TMarkdownPage ExtendedSyntaxRemoved(TMarkdownPage page) { - page.Text = ExtendedSyntaxRemoved(page.Text); - for (auto& [_, section] : page.SectionsByAnchor) { - section.Body = ExtendedSyntaxRemoved(std::move(section.Body)); - } - return page; +TMarkdownPage ExtendedSyntaxRemoved(TMarkdownPage page) { + page.Text = ExtendedSyntaxRemoved(page.Text); + for (auto& [_, section] : page.SectionsByAnchor) { + section.Body = ExtendedSyntaxRemoved(std::move(section.Body)); } + return page; +} - TPages ParsePages(TResourcesByRelativePath resources) { - TPages pages; - for (auto& [path, resource] : resources) { - TMarkdownPage page = ParseMarkdownPage(std::move(resource)); - pages.emplace(std::move(path), std::move(page)); - } - return pages; +TPages ParsePages(TResourcesByRelativePath resources) { + TPages pages; + for (auto& [path, resource] : resources) { + TMarkdownPage page = ParseMarkdownPage(std::move(resource)); + pages.emplace(std::move(path), std::move(page)); } + return pages; +} - TPages Resolved(TPages pages, TStringBuf baseURL) { - for (auto& [relativeURL, page] : pages) { - page = Resolved(relativeURL, std::move(page), baseURL); - } - return pages; +TPages Resolved(TPages pages, TStringBuf baseURL) { + for (auto& [relativeURL, page] : pages) { + page = Resolved(relativeURL, std::move(page), baseURL); } + return pages; +} - TPages ExtendedSyntaxRemoved(TPages pages) { - for (auto& [_, page] : pages) { - page = ExtendedSyntaxRemoved(std::move(page)); - } - return pages; +TPages ExtendedSyntaxRemoved(TPages pages) { + for (auto& [_, page] : pages) { + page = ExtendedSyntaxRemoved(std::move(page)); } + return pages; +} } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/page.h b/yql/essentials/utils/docs/page.h index 39d569f72c8..e01939a9292 100644 --- a/yql/essentials/utils/docs/page.h +++ b/yql/essentials/utils/docs/page.h @@ -5,12 +5,12 @@ namespace NYql::NDocs { - using TPages = THashMap<TString, TMarkdownPage>; +using TPages = THashMap<TString, TMarkdownPage>; - TPages ParsePages(TResourcesByRelativePath resources); +TPages ParsePages(TResourcesByRelativePath resources); - TPages Resolved(TPages pages, TStringBuf baseURL); +TPages Resolved(TPages pages, TStringBuf baseURL); - TPages ExtendedSyntaxRemoved(TPages pages); +TPages ExtendedSyntaxRemoved(TPages pages); } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/page_ut.cpp b/yql/essentials/utils/docs/page_ut.cpp index ede92785140..a11d7784a5b 100644 --- a/yql/essentials/utils/docs/page_ut.cpp +++ b/yql/essentials/utils/docs/page_ut.cpp @@ -6,8 +6,8 @@ using namespace NYql::NDocs; Y_UNIT_TEST_SUITE(PageTests) { - Y_UNIT_TEST(ResolveURL) { - TString markdown = R"( +Y_UNIT_TEST(ResolveURL) { + TString markdown = R"( # List of window functions in YQL The syntax for calling window functions is detailed in a @@ -35,26 +35,26 @@ If one of the compared arguments is 0.0, the function always returns false. End. )"; - TPages pages = {{"builtins/window", ParseMarkdownPage(markdown)}}; - pages = Resolved(std::move(pages), "https://ytsaurus.tech/docs/en/yql"); - pages = ExtendedSyntaxRemoved(std::move(pages)); - - TVector<TString> changes = { - "[separate article](https://ytsaurus.tech/docs/en/yql/builtins/window/../../syntax/window)", - "[aggregate functions](https://ytsaurus.tech/docs/en/yql/builtins/window/../aggregation)", - "[window frame](https://ytsaurus.tech/docs/en/yql/builtins/window/../../syntax/window#frame)", - "[any()](https://clickhouse.tech/docs/en/sql-reference/aggregate-functions/reference/any/)", - }; - - UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, changes.at(0)); - UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, changes.at(1)); - UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, changes.at(2)); - UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, changes.at(3)); - - UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, "the function always returns false"); - UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, "End."); - UNIT_ASSERT(!pages["builtins/window"].Text.Contains("{% note alert %}")); - UNIT_ASSERT(!pages["builtins/window"].Text.Contains("{% endnote %}")); - } + TPages pages = {{"builtins/window", ParseMarkdownPage(markdown)}}; + pages = Resolved(std::move(pages), "https://ytsaurus.tech/docs/en/yql"); + pages = ExtendedSyntaxRemoved(std::move(pages)); + + TVector<TString> changes = { + "[separate article](https://ytsaurus.tech/docs/en/yql/builtins/window/../../syntax/window)", + "[aggregate functions](https://ytsaurus.tech/docs/en/yql/builtins/window/../aggregation)", + "[window frame](https://ytsaurus.tech/docs/en/yql/builtins/window/../../syntax/window#frame)", + "[any()](https://clickhouse.tech/docs/en/sql-reference/aggregate-functions/reference/any/)", + }; + + UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, changes.at(0)); + UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, changes.at(1)); + UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, changes.at(2)); + UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, changes.at(3)); + + UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, "the function always returns false"); + UNIT_ASSERT_STRING_CONTAINS(pages["builtins/window"].Text, "End."); + UNIT_ASSERT(!pages["builtins/window"].Text.Contains("{% note alert %}")); + UNIT_ASSERT(!pages["builtins/window"].Text.Contains("{% endnote %}")); +} } // Y_UNIT_TEST_SUITE(PageTests) diff --git a/yql/essentials/utils/docs/resource.cpp b/yql/essentials/utils/docs/resource.cpp index 8ca724c432e..f453fe8975c 100644 --- a/yql/essentials/utils/docs/resource.cpp +++ b/yql/essentials/utils/docs/resource.cpp @@ -6,38 +6,38 @@ namespace NYql::NDocs { - bool IsMatching(const TResourceFilter& filter, TStringBuf key) { - return key.Contains(filter.BaseDirectorySuffix) && - key.EndsWith(filter.CutSuffix); - } - - TStringBuf RelativePath(const TResourceFilter& filter, TStringBuf key Y_LIFETIME_BOUND) { - size_t pos = key.find(filter.BaseDirectorySuffix); - YQL_ENSURE(pos != TString::npos); - pos += filter.BaseDirectorySuffix.size(); - - TStringBuf tail = TStringBuf(key).SubStr(pos); - tail.remove_suffix(filter.CutSuffix.size()); - return tail; - } - - TResourcesByRelativePath FindResources(const TResourceFilter& filter) { - YQL_ENSURE( - filter.BaseDirectorySuffix.EndsWith('/'), - "BaseDirectory should end with '/', but got '" << filter.BaseDirectorySuffix << "'"); - - TResourcesByRelativePath resources; - for (TStringBuf key : NResource::ListAllKeys()) { - if (!key.StartsWith("resfs/file/") || !IsMatching(filter, key)) { - continue; - } +bool IsMatching(const TResourceFilter& filter, TStringBuf key) { + return key.Contains(filter.BaseDirectorySuffix) && + key.EndsWith(filter.CutSuffix); +} + +TStringBuf RelativePath(const TResourceFilter& filter, TStringBuf key Y_LIFETIME_BOUND) { + size_t pos = key.find(filter.BaseDirectorySuffix); + YQL_ENSURE(pos != TString::npos); + pos += filter.BaseDirectorySuffix.size(); + + TStringBuf tail = TStringBuf(key).SubStr(pos); + tail.remove_suffix(filter.CutSuffix.size()); + return tail; +} + +TResourcesByRelativePath FindResources(const TResourceFilter& filter) { + YQL_ENSURE( + filter.BaseDirectorySuffix.EndsWith('/'), + "BaseDirectory should end with '/', but got '" << filter.BaseDirectorySuffix << "'"); + + TResourcesByRelativePath resources; + for (TStringBuf key : NResource::ListAllKeys()) { + if (!key.StartsWith("resfs/file/") || !IsMatching(filter, key)) { + continue; + } - TStringBuf path = RelativePath(filter, key); - YQL_ENSURE(!resources.contains(path)); + TStringBuf path = RelativePath(filter, key); + YQL_ENSURE(!resources.contains(path)); - resources[path] = NResource::Find(key); - } - return resources; + resources[path] = NResource::Find(key); } + return resources; +} } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/resource.h b/yql/essentials/utils/docs/resource.h index 0221b5ed9fc..3a39fbc2d71 100644 --- a/yql/essentials/utils/docs/resource.h +++ b/yql/essentials/utils/docs/resource.h @@ -6,14 +6,14 @@ namespace NYql::NDocs { - struct TResourceFilter { - TString BaseDirectorySuffix; - TString CutSuffix; - }; +struct TResourceFilter { + TString BaseDirectorySuffix; + TString CutSuffix; +}; - using TResourcesByRelativePath = THashMap<TString, TString>; +using TResourcesByRelativePath = THashMap<TString, TString>; - // Useful when YaTool ALL_RESOURCE_FILES macro is used. - TResourcesByRelativePath FindResources(const TResourceFilter& filter); +// Useful when YaTool ALL_RESOURCE_FILES macro is used. +TResourcesByRelativePath FindResources(const TResourceFilter& filter); } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/ut/ya.make b/yql/essentials/utils/docs/ut/ya.make index 3afe8f60aa8..72c013d9e29 100644 --- a/yql/essentials/utils/docs/ut/ya.make +++ b/yql/essentials/utils/docs/ut/ya.make @@ -1,5 +1,7 @@ UNITTEST_FOR(yql/essentials/utils/docs) +ENABLE(YQL_STYLE_CPP) + SRCS( markdown_ut.cpp page_ut.cpp diff --git a/yql/essentials/utils/docs/verification.cpp b/yql/essentials/utils/docs/verification.cpp index 0eaedc2a3b4..13f84a16330 100644 --- a/yql/essentials/utils/docs/verification.cpp +++ b/yql/essentials/utils/docs/verification.cpp @@ -10,121 +10,121 @@ namespace NYql::NDocs { - auto Fames = { - EFame::BadLinked, - EFame::Unknown, - EFame::Mentioned, - EFame::Documented, - }; +auto Fames = { + EFame::BadLinked, + EFame::Unknown, + EFame::Mentioned, + EFame::Documented, +}; - bool IsLikelyDocumentedAt(TString text, TString name) { - SubstGlobal(text, "_", ""); +bool IsLikelyDocumentedAt(TString text, TString name) { + SubstGlobal(text, "_", ""); - TVector<TStringBuf> tokens; - Split(name, ":.", tokens); + TVector<TStringBuf> tokens; + Split(name, ":.", tokens); - for (TStringBuf token : tokens) { - YQL_ENSURE(!token.Empty()); + for (TStringBuf token : tokens) { + YQL_ENSURE(!token.Empty()); - TMaybe<TString> normalized = NormalizedName(TString(token)); - YQL_ENSURE(normalized, "Unable to normalize " << token); + TMaybe<TString> normalized = NormalizedName(TString(token)); + YQL_ENSURE(normalized, "Unable to normalize " << token); - if (TCaseInsensitiveAsciiString(text).Contains(*normalized)) { - return true; - } + if (TCaseInsensitiveAsciiString(text).Contains(*normalized)) { + return true; } - return false; } + return false; +} - void Verify(const TLinks& links, const TPages& pages, TString name, TFameReport& report) { - TMaybe<TLinkTarget> target = Lookup(links, name); - if (!target) { - report[EFame::Unknown][std::move(name)] = "Unknown"; - return; - } - - const TMarkdownPage* page = pages.FindPtr(target->RelativePath); - if (!page) { - report[EFame::BadLinked][std::move(name)] = - TStringBuilder() - << "Page '" << target->RelativePath << "' not found"; - return; - } +void Verify(const TLinks& links, const TPages& pages, TString name, TFameReport& report) { + TMaybe<TLinkTarget> target = Lookup(links, name); + if (!target) { + report[EFame::Unknown][std::move(name)] = "Unknown"; + return; + } - if (!target->Anchor && !IsLikelyDocumentedAt(page->Text, name)) { - report[EFame::BadLinked][std::move(name)] = - TStringBuilder() - << "Absent at '" << target->RelativePath << "'"; - return; - } + const TMarkdownPage* page = pages.FindPtr(target->RelativePath); + if (!page) { + report[EFame::BadLinked][std::move(name)] = + TStringBuilder() + << "Page '" << target->RelativePath << "' not found"; + return; + } - if (!target->Anchor) { - report[EFame::Mentioned][std::move(name)] = - TStringBuilder() - << "Mentioned at '" << target->RelativePath << "'"; - return; - } + if (!target->Anchor && !IsLikelyDocumentedAt(page->Text, name)) { + report[EFame::BadLinked][std::move(name)] = + TStringBuilder() + << "Absent at '" << target->RelativePath << "'"; + return; + } - const TMarkdownSection* section = page->SectionsByAnchor.FindPtr(*target->Anchor); - if (!section) { - report[EFame::BadLinked][std::move(name)] = - TStringBuilder() - << "Section '" << *target->Anchor << "' not found " - << "at '" << target->RelativePath << "'"; - return; - } + if (!target->Anchor) { + report[EFame::Mentioned][std::move(name)] = + TStringBuilder() + << "Mentioned at '" << target->RelativePath << "'"; + return; + } - if (!IsLikelyDocumentedAt(section->Header.Content, name) && - !IsLikelyDocumentedAt(section->Body, name)) { - report[EFame::BadLinked][std::move(name)] = - TStringBuilder() - << "Absent at section '" << target << "', " - << "section header is '" << section->Header.Content << "', " - << "section prefix is '" << TStringBuf(section->Body).SubString(0, 32) << "'"; - return; - } + const TMarkdownSection* section = page->SectionsByAnchor.FindPtr(*target->Anchor); + if (!section) { + report[EFame::BadLinked][std::move(name)] = + TStringBuilder() + << "Section '" << *target->Anchor << "' not found " + << "at '" << target->RelativePath << "'"; + return; + } - report[EFame::Documented][std::move(name)] = + if (!IsLikelyDocumentedAt(section->Header.Content, name) && + !IsLikelyDocumentedAt(section->Body, name)) { + report[EFame::BadLinked][std::move(name)] = TStringBuilder() - << "Documented at '" << target << "'"; + << "Absent at section '" << target << "', " + << "section header is '" << section->Header.Content << "', " + << "section prefix is '" << TStringBuf(section->Body).SubString(0, 32) << "'"; + return; } - void ExamineShortHands(TFameReport& report, const TMap<TString, TString>& shortHands) { - for (const auto& [shorten, qualified] : shortHands) { - report[EFame::BadLinked].erase(shorten); - for (EFame fame : Fames) { - auto it = report[fame].find(qualified); - if (it != report[fame].end()) { - report[fame][shorten] = it->second; - } + report[EFame::Documented][std::move(name)] = + TStringBuilder() + << "Documented at '" << target << "'"; +} + +void ExamineShortHands(TFameReport& report, const TMap<TString, TString>& shortHands) { + for (const auto& [shorten, qualified] : shortHands) { + report[EFame::BadLinked].erase(shorten); + for (EFame fame : Fames) { + auto it = report[fame].find(qualified); + if (it != report[fame].end()) { + report[fame][shorten] = it->second; } } } +} - TFameReport Verify(TVerificationInput input) { - TFameReport report; - for (TString name : input.Names) { - Verify(input.Links, input.Pages, std::move(name), report); - } - ExamineShortHands(report, input.ShortHands); - return report; +TFameReport Verify(TVerificationInput input) { + TFameReport report; + for (TString name : input.Names) { + Verify(input.Links, input.Pages, std::move(name), report); } + ExamineShortHands(report, input.ShortHands); + return report; +} - double Coverage(const TFameReport& report, const TVector<TString>& names) { - if (!report.contains(EFame::Documented)) { - return 0; - } +double Coverage(const TFameReport& report, const TVector<TString>& names) { + if (!report.contains(EFame::Documented)) { + return 0; + } - const TStatusesByName& documented = report.at(EFame::Documented); + const TStatusesByName& documented = report.at(EFame::Documented); - size_t covered = 0; - for (const TString& name : names) { - covered += documented.contains(name) ? 1 : 0; - } - - return static_cast<double>(covered) / names.size(); + size_t covered = 0; + for (const TString& name : names) { + covered += documented.contains(name) ? 1 : 0; } + return static_cast<double>(covered) / names.size(); +} + } // namespace NYql::NDocs template <> diff --git a/yql/essentials/utils/docs/verification.h b/yql/essentials/utils/docs/verification.h index 4eac54017f8..0f9a2aa8214 100644 --- a/yql/essentials/utils/docs/verification.h +++ b/yql/essentials/utils/docs/verification.h @@ -8,26 +8,26 @@ namespace NYql::NDocs { - enum class EFame { - BadLinked, - Unknown, - Mentioned, - Documented, - }; +enum class EFame { + BadLinked, + Unknown, + Mentioned, + Documented, +}; - using TStatusesByName = TMap<TString, TString>; +using TStatusesByName = TMap<TString, TString>; - using TFameReport = THashMap<EFame, TStatusesByName>; +using TFameReport = THashMap<EFame, TStatusesByName>; - struct TVerificationInput { - TLinks Links; - TPages Pages; - TSet<TString> Names; - TMap<TString, TString> ShortHands; - }; +struct TVerificationInput { + TLinks Links; + TPages Pages; + TSet<TString> Names; + TMap<TString, TString> ShortHands; +}; - TFameReport Verify(TVerificationInput input); +TFameReport Verify(TVerificationInput input); - double Coverage(const TFameReport& report, const TVector<TString>& names); +double Coverage(const TFameReport& report, const TVector<TString>& names); } // namespace NYql::NDocs diff --git a/yql/essentials/utils/docs/ya.make b/yql/essentials/utils/docs/ya.make index 6f828c1434b..40cc3862c93 100644 --- a/yql/essentials/utils/docs/ya.make +++ b/yql/essentials/utils/docs/ya.make @@ -1,5 +1,7 @@ LIBRARY() +ENABLE(YQL_STYLE_CPP) + SRCS( link_page.cpp link.cpp |