Skip to content

Commit

Permalink
Merge 120d29d into 55c1ec0
Browse files Browse the repository at this point in the history
  • Loading branch information
graingert committed Sep 7, 2018
2 parents 55c1ec0 + 120d29d commit 75fd78b
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 111 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ django_js_reverse/tests/tmp/
.project
.pydevproject
.settings/

index.js
index.mjs
33 changes: 28 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
sudo: false
language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"

- "pypy"
- "pypy3"
matrix:
include:
- language: python
python: "3.7"
dist: xenial
sudo: true

install:
- nvm install --lts
- nvm use --lts
- pip install -q tox coverage coveralls tox-travis
- mkdir travis-phantomjs
- wget https://s3.amazonaws.com/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2 -O $PWD/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2
- tar -xvf $PWD/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2 -C $PWD/travis-phantomjs
- export PATH=$PWD/travis-phantomjs:$PATH

script:
- coverage erase
Expand All @@ -26,6 +27,28 @@ after_success:
- coverage combine
- coveralls

before_deploy:
- git stash --all
- ./prepare_npm.py
_deploy_provider: &_deploy_provider
skip_cleanup: true
on:
tags: true
repo: ierror/django-js-reverse
python: "3.7"
deploy:
- <<: *_deploy_provider
provider: pypi
distributions: sdist bdist_wheel
user: boerni
password: "TODO: add password"
- <<: *_deploy_provider
provider: npm
email: mboerni@gmail.com
api_key: "TODO: add api_key"

cache: pip

notifications:
email:
- boerni@gmail.com
38 changes: 33 additions & 5 deletions django_js_reverse/core.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import json
import re
import sys
from distutils.version import StrictVersion
Expand All @@ -7,6 +8,7 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.template import loader
from django.utils.encoding import force_text

from . import rjsmin
from .js_reverse_settings import (JS_EXCLUDE_NAMESPACES, JS_GLOBAL_OBJECT_NAME,
Expand Down Expand Up @@ -98,6 +100,26 @@ def prepare_url_list(urlresolver, namespace_path='', namespace=''):
yield x


def generate_json(default_urlresolver, script_prefix=None):
if script_prefix is None:
script_prefix = urlresolvers.get_script_prefix()

urls = sorted(list(prepare_url_list(default_urlresolver)))

return {
'urls': [
[
force_text(name),
[
[force_text(path), [force_text(arg) for arg in args]]
for path, args in patterns
],
] for name, patterns in urls
],
'prefix': script_prefix,
}


def generate_js(default_urlresolver):
js_var_name = getattr(settings, 'JS_REVERSE_JS_VAR_NAME', JS_VAR_NAME)
if not JS_IDENTIFIER_RE.match(js_var_name.upper()):
Expand All @@ -121,15 +143,21 @@ def generate_js(default_urlresolver):
if not script_prefix.endswith('/'):
script_prefix = '{0}/'.format(script_prefix)
else:
script_prefix = urlresolvers.get_script_prefix()
script_prefix = None

data = generate_json(default_urlresolver, script_prefix)
js_content = loader.render_to_string('django_js_reverse/urls_js.tpl', {
'urls': sorted(list(prepare_url_list(default_urlresolver))),
'url_prefix': script_prefix,
'js_var_name': js_var_name,
'js_global_object_name': js_global_object_name,
'data': json.dumps(data),
'js_name': '.'.join([js_global_object_name, js_var_name]),
})

if minfiy:
js_content = rjsmin.jsmin(js_content)
return js_content


def generate_cjs_module():
return loader.render_to_string('django_js_reverse/urls_js.tpl', {
'data': json.dumps(False),
'js_name': 'module.exports',
})
153 changes: 68 additions & 85 deletions django_js_reverse/templates/django_js_reverse/urls_js.tpl
Original file line number Diff line number Diff line change
@@ -1,114 +1,97 @@
{{ js_global_object_name }}.{{ js_var_name }} = (function () {
var Urls = {};

var self = {
url_patterns:{}
};

var _get_url = function (url_pattern) {
{{ js_name }} = (function () {
"use strict";
var data = JSON.parse('{{ data|escapejs }}');
function factory(d) {
var url_patterns = d.urls;
var url_prefix = d.prefix;
var Urls = {};
var self_url_patterns = {};

var _get_url = function (url_pattern) {
return function () {
var _arguments, index, url, url_arg, url_args, _i, _len, _ref,
_ref_list, match_ref, provided_keys, build_kwargs;
_ref_list, match_ref, provided_keys, build_kwargs;
_arguments = arguments;
_ref_list = self.url_patterns[url_pattern];
_ref_list = self_url_patterns[url_pattern];
if (arguments.length == 1 && typeof (arguments[0]) == "object") {
// kwargs mode
var provided_keys_list = Object.keys (arguments[0]);
provided_keys = {};
for (_i = 0; _i < provided_keys_list.length; _i++)
provided_keys[provided_keys_list[_i]] = 1;

match_ref = function (ref)
{
var _i;
// Verify that they have the same number of arguments
if (ref[1].length != provided_keys_list.length)
return false;
for (_i = 0;
_i < ref[1].length && ref[1][_i] in provided_keys;
_i++);
// If for loop completed, we have all keys
return _i == ref[1].length;
}
// kwargs mode
var provided_keys_list = Object.keys (arguments[0]);
provided_keys = {};
for (_i = 0; _i < provided_keys_list.length; _i++)
provided_keys[provided_keys_list[_i]] = 1;

match_ref = function (ref)
{
var _i;
// Verify that they have the same number of arguments
if (ref[1].length != provided_keys_list.length)
return false;
for (_i = 0;
_i < ref[1].length && ref[1][_i] in provided_keys;
_i++);
build_kwargs = function (keys) {return _arguments[0];}
// If for loop completed, we have all keys
return _i == ref[1].length;
}

} else {
// args mode
match_ref = function (ref)
{
return ref[1].length == _arguments.length;
}
build_kwargs = function (keys) {return _arguments[0];}

build_kwargs = function (keys) {
var kwargs = {};
} else {
// args mode
match_ref = function (ref)
{
return ref[1].length == _arguments.length;
}

for (var i = 0; i < keys.length; i++) {
kwargs[keys[i]] = _arguments[i];
}
build_kwargs = function (keys) {
var kwargs = {};

return kwargs;
for (var i = 0; i < keys.length; i++) {
kwargs[keys[i]] = _arguments[i];
}

return kwargs;
}
}

for (_i = 0;
_i < _ref_list.length && !match_ref(_ref_list[_i]);
_i++);
_i < _ref_list.length && !match_ref(_ref_list[_i]);
_i++);

// can't find a match
if (_i == _ref_list.length)
return null;
return null;

_ref = _ref_list[_i];
url = _ref[0], url_args = build_kwargs(_ref[1]);
for (url_arg in url_args) {
var url_arg_value = url_args[url_arg];
if (url_arg_value === undefined || url_arg_value === null) {
url_arg_value = '';
} else {
url_arg_value = url_arg_value.toString();
}
url = url.replace("%(" + url_arg + ")s", url_arg_value);
var url_arg_value = url_args[url_arg];
if (url_arg_value === undefined || url_arg_value === null) {
url_arg_value = '';
} else {
url_arg_value = url_arg_value.toString();
}
return '{{url_prefix|escapejs}}' + url;
url = url.replace("%(" + url_arg + ")s", url_arg_value);
}
return url_prefix + url;
};
};
};

var name, pattern, url, url_patterns, _i, _len, _ref;
url_patterns = [
{% for name, patterns in urls %}
[
'{{name|escapejs}}',
[
{% for path, args in patterns %}
[
'{{path|escapejs}}',
[
{% for arg in args %}
'{{arg|escapejs}}',
{% endfor %}
]{% if not forloop.last %},{% endif %}
]{% if not forloop.last %},{% endif %}
{% endfor %}
]{% if not forloop.last %},{% endif %}
]{% if not forloop.last %},{% endif %}
{% endfor %}
];

self.url_patterns = {};
for (_i = 0, _len = url_patterns.length; _i < _len; _i++) {

var name, pattern, url, _i, _len, _ref;
for (_i = 0, _len = url_patterns.length; _i < _len; _i++) {
_ref = url_patterns[_i], name = _ref[0], pattern = _ref[1];
self.url_patterns[name] = pattern;
self_url_patterns[name] = pattern;
url = _get_url(name);
Urls[name] = url;
Urls[name.replace(/[-_]+(.)/g, function (_m, p1) { return p1.toUpperCase(); })] = url;
Urls[name.replace(/-/g, '_')] = url;
}
Urls[name] = url;
}

return Urls;
return Urls;
}
return data ? factory(data) : factory;
})();
25 changes: 14 additions & 11 deletions django_js_reverse/tests/unit_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import json
import os
import re
import subprocess
import sys
import unittest

Expand All @@ -13,7 +16,6 @@
from django.template import Context, RequestContext, Template
from django.utils.encoding import smart_str
from helper import is_django_ver_gte_2
from selenium.webdriver.phantomjs.webdriver import WebDriver
from utils import script_prefix

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..') + os.sep)
Expand All @@ -23,35 +25,36 @@
from django.test.client import Client # noqa: E402 isort:skip
from django.test.utils import override_settings # noqa: E402 isort:skip


class AbstractJSReverseTestCase(object):
client = Client()
selenium = WebDriver()

@classmethod
def setUpClass(cls):
if hasattr(django, 'setup'):
# for django >= 1.7
django.setup()
cls.selenium = WebDriver()
super(AbstractJSReverseTestCase, cls).setUpClass()

@classmethod
def tearDownClass(cls):
cls.selenium.quit()
super(AbstractJSReverseTestCase, cls).tearDownClass()

def assertEqualJSUrlEval(self, url_call, expected_url):
response = self.client.post('/jsreverse/')
self.assertEqual(self.selenium.execute_script('%s return %s;' % (smart_str(response.content), url_call)),
expected_url)
script = '{}return {};'.format(smart_str(response.content), url_call)
module = 'console.log(new Function({})());'.format(json.dumps(script))
stdout = (
subprocess
.check_output(['node', '-e', module.encode('utf8')])
.decode('utf8')
)
self.assertEqual(re.sub(r'\n$', '', stdout), expected_url)


@override_settings(ROOT_URLCONF='django_js_reverse.tests.test_urls')
class JSReverseViewTestCaseMinified(AbstractJSReverseTestCase, TestCase):
def test_view_no_url_args(self):
self.assertEqualJSUrlEval('Urls.test_no_url_args()', '/test_no_url_args/')

def test_camel_case(self):
self.assertEqualJSUrlEval('Urls.testNoUrlArgs()', '/test_no_url_args/')

def test_view_one_url_arg(self):
self.assertEqualJSUrlEval('Urls.test_one_url_args("arg_one")', '/test_one_url_args/arg_one/')

Expand Down

0 comments on commit 75fd78b

Please sign in to comment.