diff options
| author | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
|---|---|---|
| committer | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
| commit | bce557cc2dc767628bed6aac87301a1be7c5431b (patch) | |
| tree | b51a051228d01fe3306cd7626d4a96768aadb944 /node_modules/@jet-app/app-store/tmp/src/foundation/routing | |
init commit
Diffstat (limited to 'node_modules/@jet-app/app-store/tmp/src/foundation/routing')
| -rw-r--r-- | node_modules/@jet-app/app-store/tmp/src/foundation/routing/routing-components.js | 318 |
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 |
