Source code for cdh.core.js_urls.serializer

"""
    JS URLs serializer
    ==================

    This module defiine helper functions allowing to convert the URLs that are associated with the
    names or namespaces defined in the settings to JSON. The resulting JSON will be used by a
    Javascript module to provide reverse-like functionality.

"""

import json
import re
from urllib.parse import urljoin

from django.urls import get_resolver

from .conf import settings
from .utils.compat import RegexPattern, RoutePattern, URLPattern, URLResolver
from .utils.text import replace


url_arg_re = re.compile(r'(\(.*?\))')
url_kwarg_re = re.compile(r'(\(\?P\<(.*?)\>.*?\))')
url_optional_char_re = re.compile(r'(?:\w|/)(?:\?|\*)')
url_optional_group_re = re.compile(r'\(\?\:.*\)(?:\?|\*)')
url_path_re = re.compile(r'<(.*?)>')


[docs]def get_urls_as_json(resolver=None): """ Returns the URLs associated with an URL resover as JSON. This function will traverse the tree of URLs of an URL resolver in order to return a JSON containing the correspondance between fully qualified URL names and the related paths. Only URLs that are configured to be serialized are included in the final JSON. """ resolver = resolver or get_resolver() return json.dumps(dict(_parse_resolver(resolver)))
def _parse_resolver(resolver, current_namespace=None, url_prefix=None, include_all=False): if current_namespace and resolver.namespace: ns = '{}:{}'.format(current_namespace, resolver.namespace) elif current_namespace: ns = current_namespace elif resolver.namespace: ns = resolver.namespace else: ns = "" # Include all if parameter is true, the namespace has been added to URLS, or URLS is empty include_all = include_all or (ns in settings.URLS) or len(settings.URLS) == 0 urls = [] for url_pattern in resolver.url_patterns: if isinstance(url_pattern, URLResolver): new_url_prefix = _prepare_url_part(url_pattern) new_url_prefix = ( '/' + new_url_prefix if url_prefix is None else urljoin(url_prefix or '/', new_url_prefix) ) urls = urls + _parse_resolver( url_pattern, current_namespace=ns, url_prefix=new_url_prefix, include_all=include_all, ) elif isinstance(url_pattern, URLPattern) and url_pattern.name: url_name = '{}:{}'.format(ns, url_pattern.name) if ns else url_pattern.name if url_name in settings.URLS or include_all: full_url = _prepare_url_part(url_pattern) urls.append((url_name, urljoin(url_prefix or '/', full_url))) return urls def _prepare_url_part(url_pattern): url = '' if hasattr(url_pattern, 'regex'): # pragma: no cover, NOTE: Django < 2.0 compatibility url = url_pattern.regex.pattern elif isinstance(url_pattern.pattern, RegexPattern): url = url_pattern.pattern._regex elif isinstance(url_pattern.pattern, RoutePattern): url = url_pattern.pattern._route final_url = replace(url, [('^', ''), ('$', '')]) # Removes optional groups from the URL pattern. optional_group_matches = url_optional_group_re.findall(final_url) final_url = ( replace(final_url, [(el, '') for el in optional_group_matches]) if optional_group_matches else final_url ) # Removes optional characters from the URL pattern. optional_char_matches = url_optional_char_re.findall(final_url) final_url = ( replace(final_url, [(el, '') for el in optional_char_matches]) if optional_char_matches else final_url ) # Identifies named URL arguments inside the URL pattern. kwarg_matches = url_kwarg_re.findall(final_url) final_url = ( replace(final_url, [(el[0], '<{}>'.format(el[1])) for el in kwarg_matches]) if kwarg_matches else final_url ) # Identifies unnamed URL arguments inside the URL pattern. args_matches = url_arg_re.findall(final_url) final_url = ( replace(final_url, [(el, '<>') for el in args_matches]) if args_matches else final_url ) # Identifies path expression and associated converters inside the URL pattern. path_matches = url_path_re.findall(final_url) final_url = ( replace(final_url, [(el, el.split(':')[-1]) for el in path_matches]) if (path_matches and not (kwarg_matches or args_matches)) else final_url ) return final_url