summaryrefslogtreecommitdiff
path: root/node_modules/@jet-app/app-store/tmp/src/foundation/routing/routing-components.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/@jet-app/app-store/tmp/src/foundation/routing/routing-components.js')
-rw-r--r--node_modules/@jet-app/app-store/tmp/src/foundation/routing/routing-components.js318
1 files changed, 318 insertions, 0 deletions
diff --git a/node_modules/@jet-app/app-store/tmp/src/foundation/routing/routing-components.js b/node_modules/@jet-app/app-store/tmp/src/foundation/routing/routing-components.js
new file mode 100644
index 0000000..28fdc48
--- /dev/null
+++ b/node_modules/@jet-app/app-store/tmp/src/foundation/routing/routing-components.js
@@ -0,0 +1,318 @@
+/**
+ * Created by km on 11/16/16.
+ */
+import * as urls from "../network/urls";
+import * as urlUtil from "./url-util";
+// endregion
+// region private URLRule helpers.
+/**
+ * Checks whether or not a given _pathComponents component contains a parameter.
+ * @param pathComponent The _pathComponents component to check.
+ * @returns true if the _pathComponents component is surrounded by curly braces; false otherwise.
+ */
+function isPathComponentParameter(pathComponent) {
+ const parameterStartIndex = pathComponent.indexOf("{");
+ const parameterEndIndex = pathComponent.indexOf("}");
+ return parameterStartIndex >= 0 && parameterEndIndex > parameterStartIndex + 1;
+}
+/**
+ * Extracts the parameter contained in a _pathComponents component.
+ * @param pathComponent A _pathComponents component surrounded by curly braces.
+ * @returns The parameter contained in the component.
+ */
+function getPathComponentParameter(pathComponent) {
+ const parameterStartIndex = pathComponent.indexOf("{");
+ const parameterEndIndex = pathComponent.indexOf("}");
+ const pathHasRequiredCurlyBraces = parameterStartIndex >= 0 && parameterEndIndex > parameterStartIndex;
+ return pathHasRequiredCurlyBraces
+ ? pathComponent.substring(parameterStartIndex + 1, parameterEndIndex)
+ : pathComponent;
+}
+/**
+ * Extracts the value from a path component, for a given internal key example:
+ * Path Component: "id123456"
+ * Internal Key: "id{id}"
+ * Return Value: "123456"
+ * @param pathComponent A _pathComponents component surrounded by curly braces.
+ * @returns The parameter contained in the component.
+ */
+export function getPathComponentParameterValueUsingInternalKey(pathComponent, internalKey) {
+ const valueStartIndex = internalKey.indexOf("{");
+ const valueEndIndex = pathComponent.length - (internalKey.length - (internalKey.indexOf("}") + 1));
+ const pathHasRequiredCurlyBraces = valueStartIndex >= 0 && valueEndIndex > valueStartIndex;
+ return pathHasRequiredCurlyBraces ? pathComponent.substring(valueStartIndex, valueEndIndex) : pathComponent;
+}
+/**
+ * Creates a mapping from key to _pathComponents component index
+ * for efficiently extracting parameters from a _pathComponents.
+ * @param rulePath The _pathComponents to create a mapping for.
+ * @returns A map of keys to _pathComponents component indexes.
+ */
+function makePathParameterMapping(rulePath) {
+ const mapping = {};
+ rulePath.forEach((ruleComponent, index) => {
+ if (isPathComponentParameter(ruleComponent)) {
+ mapping[ruleComponent] = index;
+ }
+ });
+ return mapping;
+}
+/**
+ * Normalizes a given protocol string for matching.
+ * @param protocol The protocol to match against.
+ * @returns The `protocol` with colon added if needed.
+ */
+function normalizeProtocol(protocol) {
+ // An empty string is falsy.
+ if (protocol === null || protocol === undefined) {
+ return null;
+ }
+ return protocol;
+}
+/**
+ * Creates `UrlRouteQuery` objects from substring of url.
+ * ? = optional
+ * -caseInsensitive = case insensitive
+ * @param parameters strings of form `<key>[?][-i]=<value>`.
+ * @returns Array of `UrlRouteQuery` objects.
+ */
+function parseQuery(parameters) {
+ const parsedQuery = [];
+ if (!parameters) {
+ return parsedQuery;
+ }
+ for (const param of parameters) {
+ const parts = param.split("=");
+ let key = parts[0];
+ const optional = key.indexOf("?") !== -1;
+ key = key.replace("?", "");
+ const caseInsensitive = key.indexOf("-caseInsensitive") !== -1;
+ key = key.replace("-caseInsensitive", "");
+ let value = null;
+ if (parts.length > 1) {
+ value = decodeURIComponent(parts[1]);
+ }
+ parsedQuery.push({
+ key,
+ value,
+ optional,
+ caseInsensitive,
+ });
+ }
+ return parsedQuery;
+}
+// endregion
+// region Url Rule
+/**
+ * The `UrlRule` class extracts the pattern format from `UrlRuleDefinition`s, and encapsulates
+ * the information needed to match against a candidate URL and extract parameters from it.
+ *
+ * The terminology here is:
+ * - rule: A specific url pattern.
+ * - route: A group of rules that together form a single route, i.e. UrlRule[].
+ */
+export class UrlRule {
+ /**
+ * Construct the route with all required properties.
+ * @param rule The rule to match.
+ */
+ constructor(rule) {
+ this.identifier = rule.identifier;
+ this._protocol = normalizeProtocol(rule.protocol);
+ this._hostName = rule.hostName;
+ if (rule.path) {
+ this._pathComponents = rule.path.split("/").filter((component) => component.length > 0);
+ this._pathParameterMap = makePathParameterMapping(this._pathComponents);
+ }
+ else {
+ this._pathComponents = null;
+ this._pathParameterMap = null;
+ }
+ this._pathExtension = rule.pathExtension;
+ this._query = parseQuery(rule.query);
+ this._hash = rule.hash;
+ this._regex = rule.regex;
+ if (rule.exclusions) {
+ this._exclusions = rule.exclusions.map(function (ex) {
+ return new UrlRule(ex);
+ });
+ }
+ else {
+ this._exclusions = null;
+ }
+ }
+ /**
+ * Checks whether or not the route matches a given URL.
+ * @param url The URL to check against.
+ * @returns true if the route matches `urls`; false otherwise.
+ */
+ matches(url) {
+ var _a, _b;
+ if (this._regex) {
+ if (!this._regex.length) {
+ // If the rule specifies regex but does not supply patterns, we need to return false. Otherwise, we will
+ // risk matching against everything. This is because an empty regex with no other rule parameters will
+ // cause us to fallthrough to the end and match against all URLs.
+ return false;
+ }
+ let didMatchRegex = false;
+ for (const regexPattern of this._regex) {
+ if (regexPattern.test(url.toString())) {
+ // If we match against any of regex patterns, then we should proceed.
+ // If no matches are found, then this rule is not matched.
+ didMatchRegex = true;
+ break;
+ }
+ }
+ if (!didMatchRegex) {
+ return false;
+ }
+ }
+ if (this._protocol && url.protocol !== this._protocol) {
+ return false;
+ }
+ if (this._hostName && url.host !== this._hostName) {
+ return false;
+ }
+ if (this._pathComponents) {
+ const rulePathComponents = this._pathComponents;
+ const urlPathComponents = url.pathComponents();
+ if (rulePathComponents.length !== urlPathComponents.length) {
+ return false;
+ }
+ // We're iterating two arrays here, an old style for-loop is appropriate
+ const length = rulePathComponents.length;
+ for (let i = 0; i < length; i++) {
+ const ruleComponent = rulePathComponents[i];
+ if (isPathComponentParameter(ruleComponent)) {
+ // component parameters always match
+ continue;
+ }
+ const urlComponent = urlPathComponents[i];
+ if (ruleComponent !== urlComponent) {
+ return false;
+ }
+ }
+ }
+ if (this._pathExtension) {
+ if (url.pathExtension() !== this._pathExtension) {
+ return false;
+ }
+ }
+ if (this._query) {
+ for (const param of this._query) {
+ let value;
+ if (param.caseInsensitive) {
+ for (const [queryKey, queryValue] of Object.entries((_a = url.query) !== null && _a !== void 0 ? _a : {})) {
+ if (param.key.toLocaleLowerCase() === queryKey.toLocaleLowerCase()) {
+ value = queryValue;
+ }
+ }
+ }
+ else {
+ value = (_b = url.query) === null || _b === void 0 ? void 0 : _b[param.key];
+ }
+ if (!value && !param.optional) {
+ return false;
+ }
+ if (param.value && param.value !== value) {
+ return false;
+ }
+ }
+ }
+ if (this._hash && url.hash !== this._hash) {
+ return false;
+ }
+ if (this._exclusions) {
+ for (const exclusionRule of this._exclusions) {
+ if (exclusionRule._exclusions) {
+ throw Error("Matching exclusion rules with further exclusion rules may introduce significant code-complexity and/or reduce the ease with which developers are able to reason about your desired goals. Are there any simpler options?");
+ }
+ if (exclusionRule.matches(url)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ /**
+ * Extract information from a matching url.
+ * @param matchingUrl The url to extract parameters from.
+ * @returns `Parameters` extracted from `matchingUrl`
+ * @note This function is only valid when `this.matches(matchingUrl) === true`.
+ */
+ extractParameters(matchingUrl) {
+ var _a, _b;
+ const parameters = {};
+ if (this._pathComponents !== null && this._pathParameterMap !== null) {
+ const urlPathComponents = matchingUrl.pathComponents();
+ for (const internalKey of Object.keys(this._pathParameterMap)) {
+ const externalKey = getPathComponentParameter(internalKey);
+ const index = this._pathParameterMap[internalKey];
+ const parameterValue = getPathComponentParameterValueUsingInternalKey(urlPathComponents[index], internalKey);
+ parameters[externalKey] = decodeURIComponent(parameterValue);
+ }
+ }
+ if (this._query) {
+ for (const param of this._query) {
+ parameters[param.key] = (_b = (_a = matchingUrl.query) === null || _a === void 0 ? void 0 : _a[param.key]) !== null && _b !== void 0 ? _b : undefined;
+ }
+ }
+ return parameters;
+ }
+}
+/**
+ * `UrlRouter` manages a set of url rule templates to allow `urls` to serve as keys for different associated objects (like Builders).
+ *
+ * @note This is replaces old `UrlRouter` as a synchronous way match route URLs to handlers. In contrast to the previous implementation,
+ * it maps entire objects (containing related async handlers and properties) to urls.
+ */
+export class UrlRouter {
+ /// Constructs an empty URL router object.
+ constructor() {
+ this._routeMappings = [];
+ }
+ /**
+ * Register a new route defined by a set of definitions and object on the router.
+ * @param routeDefinitions The definitions of rules to register.
+ * @param object The object for the rule.
+ */
+ associate(routeDefinitions, object) {
+ const route = [];
+ for (const definition of routeDefinitions) {
+ route.push(new UrlRule(definition));
+ }
+ this._routeMappings.push({ route: route, object: object });
+ }
+ /**
+ * Resolve given url to associated object, if any exist.
+ * @param urlOrString URL or string representation of url to resolve objects for.
+ * @returns `UrlRouterResult` containing url, extracted parameters, and associated object, or `null` if no match was found.
+ */
+ routedObjectForUrl(urlOrString) {
+ let url = typeof urlOrString === "string" ? new urls.URL(urlOrString) : urlOrString;
+ url = urlUtil.normalizedAppStoreUrl(url);
+ url = urlUtil.normalizedActionUrl(url);
+ for (const mapping of this._routeMappings) {
+ for (const rule of mapping.route) {
+ if (rule.matches(url)) {
+ return {
+ normalizedUrl: url,
+ parameters: rule.extractParameters(url),
+ object: mapping.object,
+ matchedRuleIdentifier: rule.identifier,
+ };
+ }
+ }
+ }
+ // No match. Still return a result with normalized url.
+ return {
+ normalizedUrl: url,
+ parameters: null,
+ object: null,
+ matchedRuleIdentifier: null,
+ };
+ }
+}
+// endregion
+//# sourceMappingURL=routing-components.js.map \ No newline at end of file