Skip to content

Commit

Permalink
complete parse_url_pattern implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Dec 9, 2024
1 parent 5a45e77 commit 227b410
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 19 deletions.
22 changes: 17 additions & 5 deletions include/ada/url_pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ struct url_pattern_component_result {
std::unordered_map<std::string, std::string> groups;
};

using url_pattern_input = std::variant<std::string, url_pattern_init>;
using url_pattern_input = std::variant<std::string_view, url_pattern_init>;

// A struct providing the URLPattern matching results for all
// components of a URL. The URLPatternResult API is defined as
Expand Down Expand Up @@ -212,10 +212,18 @@ class url_pattern {
std::optional<std::string_view> base_url,
std::optional<url_pattern_options> options);

std::optional<url_pattern_result> exec(std::optional<url_pattern_input> input,
std::optional<std::string> base_url);
bool test(std::optional<url_pattern_input> input,
std::optional<std::string_view> base_url);
// @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec
tl::expected<url_pattern_result, url_pattern_errors> exec(
std::variant<url_pattern_init, url_aggregator> input,
std::string_view* base_url);
// @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-test
bool test(std::variant<url_pattern_init, url_aggregator> input,
std::string_view* base_url);

// @see https://urlpattern.spec.whatwg.org/#url-pattern-match
tl::expected<url_pattern_result, url_pattern_errors> match(
std::variant<url_pattern_init, url_aggregator> input,
std::string_view* base_url_string);

// @see https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol
std::string_view get_protocol() const ada_lifetime_bound;
Expand Down Expand Up @@ -427,6 +435,10 @@ generate_regular_expression_and_name_list(
// @see https://urlpattern.spec.whatwg.org/#hostname-pattern-is-an-ipv6-address
constexpr bool is_ipv6_address(std::string_view input) noexcept;

// @see
// https://urlpattern.spec.whatwg.org/#protocol-component-matches-a-special-scheme
bool protocol_component_matches_special_scheme(std::string_view input);

} // namespace url_pattern_helpers

} // namespace ada
Expand Down
38 changes: 36 additions & 2 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1024,11 +1024,45 @@ tl::expected<url_pattern, url_pattern_errors> parse_url_pattern(
auto compile_options = url_pattern_compile_component_options::DEFAULT;
compile_options.ignore_case = options->ignore_case;

// TODO: Optimization opportunity: Simplify this if statement.
// If the result of running protocol component matches a special scheme given
// urlPattern’s protocol component is true, then:
// TODO: Complete this
if (url_pattern_helpers::protocol_component_matches_special_scheme(
url_pattern_.protocol.get_pattern())) {
// Let pathCompileOptions be copy of the pathname options with the ignore
// case property set to options["ignoreCase"].
auto path_compile_options = url_pattern_compile_component_options::HOSTNAME;
path_compile_options.ignore_case = options->ignore_case;

// Set urlPattern’s pathname component to the result of compiling a
// component given processedInit["pathname"], canonicalize a pathname, and
// pathCompileOptions.
url_pattern_.pathname = url_pattern_component::compile(
processed_init->pathname.value(),
url_pattern_helpers::canonicalize_pathname, path_compile_options);
} else {
// Otherwise set urlPattern’s pathname component to the result of compiling
// a component given processedInit["pathname"], canonicalize an opaque
// pathname, and compileOptions.
url_pattern_.pathname = url_pattern_component::compile(
processed_init->pathname.value(),
url_pattern_helpers::canonicalize_opaque_pathname, compile_options);
}

// Set urlPattern’s search component to the result of compiling a component
// given processedInit["search"], canonicalize a search, and compileOptions.
url_pattern_.search = url_pattern_component::compile(
processed_init->search.value(), url_pattern_helpers::canonicalize_search,
compile_options);

// Set urlPattern’s hash component to the result of compiling a component
// given processedInit["hash"], canonicalize a hash, and compileOptions.
url_pattern_.hash = url_pattern_component::compile(
processed_init->hash.value(), url_pattern_helpers::canonicalize_hash,
compile_options);

return tl::unexpected(url_pattern_errors::type_error);
// Return urlPattern.
return url_pattern_;
}

template url parse_url_impl(std::string_view user_input,
Expand Down
80 changes: 68 additions & 12 deletions src/url_pattern.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "ada.h"

#include <optional>
#include <regex>
#include <string>

namespace ada {
Expand Down Expand Up @@ -785,23 +786,78 @@ constexpr bool is_ipv6_address(std::string_view input) noexcept {
return false;
}

bool protocol_component_matches_special_scheme(std::string_view input) {
// TODO: Optimize this.
std::regex rx(input.begin(), input.size());
std::cmatch cmatch;
return std::regex_match("http", cmatch, rx) ||
std::regex_match("https", cmatch, rx) ||
std::regex_match("ws", cmatch, rx) ||
std::regex_match("wss", cmatch, rx) ||
std::regex_match("ftp", cmatch, rx);
}

} // namespace url_pattern_helpers

std::optional<url_pattern_result> url_pattern::exec(
std::optional<url_pattern_input> input,
std::optional<std::string> base_url) {
(void)input;
(void)base_url;
// TODO: Implement this
return std::nullopt;
// TODO: This function argument should bve url_pattern_input but the spec is
// vague.
tl::expected<url_pattern_result, url_pattern_errors> url_pattern::exec(
std::variant<url_pattern_init, url_aggregator> input,
std::string_view* base_url = nullptr) {
// Return the result of match given this's associated URL pattern, input, and
// baseURL if given.
return match(input, base_url);
}

bool url_pattern::test(std::optional<url_pattern_input> input,
std::optional<std::string_view> base_url) {
// TODO: This function argument should bve url_pattern_input but the spec is
// vague.
bool url_pattern::test(std::variant<url_pattern_init, url_aggregator> input,
std::string_view* base_url = nullptr) {
// TODO: Optimization opportunity. Rather than returning `url_pattern_result`
// Implement a fast path just like `can_parse()` in ada_url.
// Let result be the result of match given this's associated URL pattern,
// input, and baseURL if given.
auto result = match(input, base_url);
// If result is null, return false.
// Return true.
return result.has_value();
}

tl::expected<url_pattern_result, url_pattern_errors> url_pattern::match(
std::variant<url_pattern_init, url_aggregator> input,
std::string_view* base_url_string) {
std::string protocol_value{};
std::string username_value{};
std::string password_value{};
std::string hostname_value{};
std::string port_value{};
std::string pathname_value{};
std::string search_value{};
std::string hash_value{};

// Let inputs be an empty list.
// Append input to inputs.
std::vector inputs{input};

// If input is a URLPatternInit then:
if (std::holds_alternative<url_pattern_init>(input)) {
// If baseURLString was given, throw a TypeError.
if (base_url_string != nullptr) {
return tl::unexpected(url_pattern_errors::type_error);
}

// Let applyResult be the result of process a URLPatternInit given input,
// "url", protocol, username, password, hostname, port, pathname, search,
// and hash.
// TODO: If this throws an exception, catch it, and return null.
auto apply_result = url_pattern_init::process(
std::get<url_pattern_init>(input), "url", protocol_value,
username_value, password_value, hostname_value, port_value,
pathname_value, search_value, hash_value);
}

// TODO: Implement this
(void)input;
(void)base_url;
return false;
return {};
}

} // namespace ada

0 comments on commit 227b410

Please sign in to comment.