Insert semicolon between JS files, fixes a JS syntax error when certain files are combined (#813)

compressor will turn files that look like

File1.js:
(function($) { console.log("run"); })(window)

File2.js:
(function($) { console.log("run 2"); })(window)

Into:
(function($) { console.log("run"); })(window)
(function($) { console.log("run 2"); })(window)

which will give an error like "Uncaught TypeError: (intermediate value)(...) is not a function"

This commit changes that output to:

(function($) { console.log("run"); })(window);(function($) { console.log("run 2"); })(window)
This commit is contained in:
Patrick Michaud
2017-01-02 23:50:02 -08:00
committed by Johannes Linke
parent 785e62a4c9
commit c2c37c7c30
7 changed files with 82 additions and 48 deletions

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ build
compressor/tests/static/CACHE
compressor/tests/static/custom
compressor/tests/static/js/066cd253eada.js
compressor/tests/static/js/d728fc7f9301.js
compressor/tests/static/test.txt*
dist

View File

@@ -50,3 +50,20 @@ class JsCompressor(Compressor):
ret.append(subnode.output(*args, **kwargs))
return '\n'.join(ret)
return super(JsCompressor, self).output(*args, **kwargs)
def filter_input(self, forced=False):
"""
Passes each hunk (file or code) to the 'input' methods
of the compressor filters.
"""
content = []
for hunk in self.hunks(forced):
# If a file ends with a function call, say, console.log()
# but doesn't have a semicolon, and the next file starts with
# a (, the individual files are ok, but when combined you get an
# error like TypeError...
# Forcing a semicolon in between fixes it.
if settings.COMPRESS_ENABLED or forced:
hunk = ";" + hunk
content.append(hunk)
return content

View File

@@ -208,12 +208,12 @@ class CompressorTestCase(SimpleTestCase):
self.assertEqual(out, list(self.js_node.hunks()))
def test_js_output(self):
out = '<script type="text/javascript" src="/static/CACHE/js/066cd253eada.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/d728fc7f9301.js"></script>'
self.assertEqual(out, self.js_node.output())
def test_js_override_url(self):
self.js_node.context.update({'url': 'This is not a url, just a text'})
out = '<script type="text/javascript" src="/static/CACHE/js/066cd253eada.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/d728fc7f9301.js"></script>'
self.assertEqual(out, self.js_node.output())
def test_css_override_url(self):
@@ -226,22 +226,22 @@ class CompressorTestCase(SimpleTestCase):
self.assertEqualCollapsed(self.js, self.js_node.output())
def test_js_return_if_on(self):
output = '<script type="text/javascript" src="/static/CACHE/js/066cd253eada.js"></script>'
output = '<script type="text/javascript" src="/static/CACHE/js/d728fc7f9301.js"></script>'
self.assertEqual(output, self.js_node.output())
@override_settings(COMPRESS_OUTPUT_DIR='custom')
def test_custom_output_dir1(self):
output = '<script type="text/javascript" src="/static/custom/js/066cd253eada.js"></script>'
output = '<script type="text/javascript" src="/static/custom/js/d728fc7f9301.js"></script>'
self.assertEqual(output, JsCompressor(self.js).output())
@override_settings(COMPRESS_OUTPUT_DIR='')
def test_custom_output_dir2(self):
output = '<script type="text/javascript" src="/static/js/066cd253eada.js"></script>'
output = '<script type="text/javascript" src="/static/js/d728fc7f9301.js"></script>'
self.assertEqual(output, JsCompressor(self.js).output())
@override_settings(COMPRESS_OUTPUT_DIR='/custom/nested/')
def test_custom_output_dir3(self):
output = '<script type="text/javascript" src="/static/custom/nested/js/066cd253eada.js"></script>'
output = '<script type="text/javascript" src="/static/custom/nested/js/d728fc7f9301.js"></script>'
self.assertEqual(output, JsCompressor(self.js).output())
@override_settings(COMPRESS_PRECOMPILERS=(
@@ -353,6 +353,21 @@ class JsAsyncDeferTestCase(SimpleTestCase):
self.assertEqual(output, attrs)
class JSWithParensTestCase(SimpleTestCase):
def setUp(self):
self.js = """
<script src="/static/js/one.js"></script>
<script src="/static/js/two.js"></script>
"""
def test_js_content(self):
js_node = JsCompressor(self.js)
content = js_node.filter_input()
self.assertEqual(content[0], ';obj = {};')
self.assertEqual(content[1], ';pollos = {}')
class CacheTestCase(SimpleTestCase):
def setUp(self):

View File

@@ -101,7 +101,7 @@ class TestJinja2CompressorExtension(TestCase):
<script type="text/javascript" charset="utf-8">obj.value = "value";</script>
{% endcompress %}""")
context = {'STATIC_URL': settings.COMPRESS_URL}
out = '<script type="text/javascript" src="/static/CACHE/js/066cd253eada.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/d728fc7f9301.js"></script>'
self.assertEqual(out, template.render(context))
def test_nonascii_js_tag(self):
@@ -110,7 +110,7 @@ class TestJinja2CompressorExtension(TestCase):
<script type="text/javascript" charset="utf-8">var test_value = "\u2014";</script>
{% endcompress %}""")
context = {'STATIC_URL': settings.COMPRESS_URL}
out = '<script type="text/javascript" src="/static/CACHE/js/e214fe629b28.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/d34f30e02e70.js"></script>'
self.assertEqual(out, template.render(context))
def test_nonascii_latin1_js_tag(self):
@@ -119,7 +119,7 @@ class TestJinja2CompressorExtension(TestCase):
<script type="text/javascript">var test_value = "\u2014";</script>
{% endcompress %}""")
context = {'STATIC_URL': settings.COMPRESS_URL}
out = '<script type="text/javascript" src="/static/CACHE/js/be9e078b5ca7.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/a830bddd3636.js"></script>'
self.assertEqual(out, template.render(context))
def test_css_inline(self):
@@ -140,7 +140,7 @@ class TestJinja2CompressorExtension(TestCase):
<script type="text/javascript" charset="utf-8">obj.value = "value";</script>
{% endcompress %}""")
context = {'STATIC_URL': settings.COMPRESS_URL}
out = '<script type="text/javascript">obj={};obj.value="value";</script>'
out = '<script type="text/javascript">;obj={};;obj.value="value";</script>'
self.assertEqual(out, template.render(context))
def test_nonascii_inline_css(self):

View File

@@ -8,7 +8,7 @@ class TestMtimeCacheCommand(TestCase):
# FIXME: add actual tests, improve the existing ones.
exclusion_patterns = [
'*CACHE*', '*custom*', '*066cd253eada.js', 'test.txt*'
'*CACHE*', '*custom*', '*d728fc7f9301.js', 'test.txt*'
]
def default_ignore(self):

View File

@@ -214,7 +214,7 @@ class OfflineTestCaseMixin(object):
class OfflineCompressBasicTestCase(OfflineTestCaseMixin, TestCase):
templates_dir = 'basic'
expected_hash = 'f5e179b8eca4'
expected_hash = 'a2d34b854194'
@patch.object(CompressCommand, 'compress')
def test_handle_no_args(self, compress_mock):
@@ -305,7 +305,7 @@ class OfflineCompressSkipDuplicatesTestCase(OfflineTestCaseMixin, TestCase):
# Only one block compressed, the second identical one was skipped.
self.assertEqual(1, count)
# Only 1 <script> block in returned result as well.
self.assertEqual([self._render_script('f5e179b8eca4')], result)
self.assertEqual([self._render_script('a2d34b854194')], result)
rendered_template = self._render_template(engine)
# But rendering the template returns both (identical) scripts.
self.assertEqual(
@@ -314,7 +314,7 @@ class OfflineCompressSkipDuplicatesTestCase(OfflineTestCaseMixin, TestCase):
class OfflineCompressBlockSuperTestCase(OfflineTestCaseMixin, TestCase):
templates_dir = 'test_block_super'
expected_hash = '7c02d201f69d'
expected_hash = '09424aa0fc45'
# Block.super not supported for Jinja2 yet.
engines = ('django',)
@@ -322,7 +322,7 @@ class OfflineCompressBlockSuperTestCase(OfflineTestCaseMixin, TestCase):
class OfflineCompressBlockSuperMultipleTestCase(
OfflineTestCaseMixin, TestCase):
templates_dir = 'test_block_super_multiple'
expected_hash = 'f8891c416981'
expected_hash = '86520b469e89'
# Block.super not supported for Jinja2 yet.
engines = ('django',)
@@ -330,7 +330,7 @@ class OfflineCompressBlockSuperMultipleTestCase(
class OfflineCompressBlockSuperMultipleCachedLoaderTestCase(
OfflineTestCaseMixin, TestCase):
templates_dir = 'test_block_super_multiple_cached'
expected_hash = '2f6ef61c488e'
expected_hash = 'd31f4d9bbd99'
# Block.super not supported for Jinja2 yet.
engines = ('django',)
additional_test_settings = {
@@ -354,8 +354,8 @@ class OfflineCompressBlockSuperTestCaseWithExtraContent(
log=self.log, verbosity=self.verbosity, engine=engine)
self.assertEqual(2, count)
self.assertEqual([
self._render_script('ced14aec5856'),
self._render_script('7c02d201f69d')
self._render_script('85482ad42724'),
self._render_script('09424aa0fc45')
], result)
rendered_template = self._render_template(engine)
self.assertEqual(rendered_template, self._render_result(result, ''))
@@ -363,7 +363,7 @@ class OfflineCompressBlockSuperTestCaseWithExtraContent(
class OfflineCompressConditionTestCase(OfflineTestCaseMixin, TestCase):
templates_dir = 'test_condition'
expected_hash = '4e3758d50224'
expected_hash = '2b3ab9ad7158'
additional_test_settings = {
'COMPRESS_OFFLINE_CONTEXT': {
'condition': 'red',
@@ -373,17 +373,17 @@ class OfflineCompressConditionTestCase(OfflineTestCaseMixin, TestCase):
class OfflineCompressTemplateTagTestCase(OfflineTestCaseMixin, TestCase):
templates_dir = 'test_templatetag'
expected_hash = 'a27e1d3a619a'
expected_hash = 'a62a1cfcd3b5'
class OfflineCompressStaticTemplateTagTestCase(OfflineTestCaseMixin, TestCase):
templates_dir = 'test_static_templatetag'
expected_hash = 'dfa2bb387fa8'
expected_hash = 'c6ecb8d4ce7e'
class OfflineCompressTestCaseWithContext(OfflineTestCaseMixin, TestCase):
templates_dir = 'test_with_context'
expected_hash = '5838e2fd66af'
expected_hash = '0b939b10df08'
additional_test_settings = {
'COMPRESS_OFFLINE_CONTEXT': {
'content': 'OK!',
@@ -393,7 +393,7 @@ class OfflineCompressTestCaseWithContext(OfflineTestCaseMixin, TestCase):
class OfflineCompressTestCaseWithContextSuper(OfflineTestCaseMixin, TestCase):
templates_dir = 'test_with_context_super'
expected_hash = 'b1d0a333a4ef'
expected_hash = '9fad27eba458'
additional_test_settings = {
'COMPRESS_OFFLINE_CONTEXT': {
'content': 'OK!',
@@ -405,7 +405,7 @@ class OfflineCompressTestCaseWithContextSuper(OfflineTestCaseMixin, TestCase):
class OfflineCompressTestCaseWithContextList(OfflineTestCaseMixin, TestCase):
templates_dir = 'test_with_context'
expected_hash = ['f8bcaea049b3', 'db12749b1e80', 'e9f4a0054a06']
expected_hash = ['a92d67d3304a', '0ad21f77e74e', 'a3598381c14f']
additional_test_settings = {
'COMPRESS_OFFLINE_CONTEXT': list(offline_context_generator())
}
@@ -421,7 +421,7 @@ class OfflineCompressTestCaseWithContextList(OfflineTestCaseMixin, TestCase):
class OfflineCompressTestCaseWithContextListSuper(
OfflineCompressTestCaseWithContextList):
templates_dir = 'test_with_context_super'
expected_hash = ['b11543f1e174', 'aedf6d2a7ec7', '0dbb8c29f23a']
expected_hash = ['1a40a7565816', 'f91a43f26ad3', 'b6e00dc2000c']
additional_test_settings = {
'COMPRESS_OFFLINE_CONTEXT': list(offline_context_generator())
}
@@ -432,7 +432,7 @@ class OfflineCompressTestCaseWithContextListSuper(
class OfflineCompressTestCaseWithContextGenerator(
OfflineTestCaseMixin, TestCase):
templates_dir = 'test_with_context'
expected_hash = ['f8bcaea049b3', 'db12749b1e80', 'e9f4a0054a06']
expected_hash = ['a92d67d3304a', '0ad21f77e74e', 'a3598381c14f']
additional_test_settings = {
'COMPRESS_OFFLINE_CONTEXT': 'compressor.tests.test_offline.'
'offline_context_generator'
@@ -451,7 +451,7 @@ class OfflineCompressTestCaseWithContextGenerator(
class OfflineCompressTestCaseWithContextGeneratorSuper(
OfflineCompressTestCaseWithContextGenerator):
templates_dir = 'test_with_context_super'
expected_hash = ['b11543f1e174', 'aedf6d2a7ec7', '0dbb8c29f23a']
expected_hash = ['1a40a7565816', 'f91a43f26ad3', 'b6e00dc2000c']
additional_test_settings = {
'COMPRESS_OFFLINE_CONTEXT': 'compressor.tests.test_offline.'
'offline_context_generator'
@@ -470,7 +470,7 @@ class OfflineCompressStaticUrlIndependenceTestCase(
STATIC_URL is not cached when rendering the template.
"""
templates_dir = 'test_static_url_independence'
expected_hash = '44ed960a3d1d'
expected_hash = '12772534f095'
additional_test_settings = {
'STATIC_URL': '/custom/static/url/',
'COMPRESS_OFFLINE_CONTEXT': (
@@ -497,7 +497,7 @@ class OfflineCompressStaticUrlIndependenceTestCase(
class OfflineCompressTestCaseWithContextVariableInheritance(
OfflineTestCaseMixin, TestCase):
templates_dir = 'test_with_context_variable_inheritance'
expected_hash = 'ea3267f3e9dd'
expected_hash = 'fbf0ed0604e3'
additional_test_settings = {
'COMPRESS_OFFLINE_CONTEXT': {
'parent_template': 'base.html',
@@ -520,7 +520,7 @@ class OfflineCompressTestCaseWithContextVariableInheritanceSuper(
'parent_template': 'base2.html',
}]
}
expected_hash = ['7d1416cab12e', 'a31eb23d0157']
expected_hash = ['11c0a6708293', '3bb007b509b3']
# Block.super not supported for Jinja2 yet.
engines = ('django',)
@@ -587,8 +587,8 @@ class OfflineCompressTestCaseErrors(OfflineTestCaseMixin, TestCase):
self.assertIn(self._render_link('78bd7a762e2d'), result)
self.assertIn(self._render_link('e31030430724'), result)
self.assertIn(self._render_script('3872c9ae3f42'), result)
self.assertIn(self._render_script('cd8870829421'), result)
self.assertIn(self._render_script('e847d9758dbf'), result)
self.assertIn(self._render_script('1c8d9c2db1fb'), result)
class OfflineCompressTestCaseWithError(OfflineTestCaseMixin, TestCase):
@@ -620,7 +620,7 @@ class OfflineCompressEmptyTag(OfflineTestCaseMixin, TestCase):
compressor encounters such an emptystring in the manifest.
"""
templates_dir = 'basic'
expected_hash = 'f5e179b8eca4'
expected_hash = 'a2d34b854194'
engines = ('django',)
def _test_offline(self, engine):
@@ -635,7 +635,8 @@ class OfflineCompressBlockSuperBaseCompressed(OfflineTestCaseMixin, TestCase):
template_names = ['base.html', 'base2.html',
'test_compressor_offline.html']
templates_dir = 'test_block_super_base_compressed'
expected_hash = ['028c3fc42232', '2e9d3f5545a6', 'f8891c416981']
expected_hash_offline = ['e74d9424467d', '9df645ef1c05', '86520b469e89']
expected_hash = ['028c3fc42232', '2e9d3f5545a6', '86520b469e89']
# Block.super not supported for Jinja2 yet.
engines = ('django',)
@@ -665,7 +666,7 @@ class OfflineCompressBlockSuperBaseCompressed(OfflineTestCaseMixin, TestCase):
count, result = CompressCommand().compress(
log=self.log, verbosity=self.verbosity, engine=engine)
self.assertEqual(len(self.expected_hash), count)
for expected_hash, template in zip(self.expected_hash, self.templates):
for expected_hash, template in zip(self.expected_hash_offline, self.templates):
expected = self._render_script(expected_hash)
self.assertIn(expected, result)
rendered_template = self._render_template(template, engine)
@@ -705,9 +706,9 @@ class OfflineCompressComplexTestCase(OfflineTestCaseMixin, TestCase):
log=self.log, verbosity=self.verbosity, engine=engine)
self.assertEqual(3, count)
self.assertEqual([
self._render_script('0e8807bebcee'),
self._render_script('eed1d222933e'),
self._render_script('00b4baffe335')
self._render_script('ea8d7c940f0d'),
self._render_script('10ae6904bcc6'),
self._render_script('8c7c068d5973')
], result)
rendered_template = self._render_template(engine)
self.assertEqual(
@@ -763,18 +764,18 @@ class TestCompressCommand(OfflineTestCaseMixin, TestCase):
call_command('compress', engines=["django"], **opts)
manifest_django = get_offline_manifest()
manifest_django_expected = self._build_expected_manifest(
{'8464063aa0729700fca0452e009582af': '662b9ce354e4'})
{'8464063aa0729700fca0452e009582af': 'f3bfcd635b36'})
self.assertEqual(manifest_django, manifest_django_expected)
call_command('compress', engines=["jinja2"], **opts)
manifest_jinja2 = get_offline_manifest()
manifest_jinja2_expected = self._build_expected_manifest(
{'0ec631f01496b28bbecad129c5532db4': '3cd63e8c4360'})
{'0ec631f01496b28bbecad129c5532db4': '9ddf4527a67d'})
self.assertEqual(manifest_jinja2, manifest_jinja2_expected)
call_command('compress', engines=["django", "jinja2"], **opts)
manifest_both = get_offline_manifest()
manifest_both_expected = self._build_expected_manifest(
{'8464063aa0729700fca0452e009582af': '662b9ce354e4',
'0ec631f01496b28bbecad129c5532db4': '3cd63e8c4360'})
{'8464063aa0729700fca0452e009582af': 'f3bfcd635b36',
'0ec631f01496b28bbecad129c5532db4': '9ddf4527a67d'})
self.assertEqual(manifest_both, manifest_both_expected)

View File

@@ -89,7 +89,7 @@ class TemplatetagTestCase(TestCase):
<script type="text/javascript">obj.value = "value";</script>
{% endcompress %}
"""
out = '<script type="text/javascript" src="/static/CACHE/js/066cd253eada.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/d728fc7f9301.js"></script>'
self.assertEqual(out, render(template, self.context))
def test_nonascii_js_tag(self):
@@ -98,7 +98,7 @@ class TemplatetagTestCase(TestCase):
<script type="text/javascript">var test_value = "\u2014";</script>
{% endcompress %}
"""
out = '<script type="text/javascript" src="/static/CACHE/js/e214fe629b28.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/d34f30e02e70.js"></script>'
self.assertEqual(out, render(template, self.context))
def test_nonascii_latin1_js_tag(self):
@@ -107,7 +107,7 @@ class TemplatetagTestCase(TestCase):
<script type="text/javascript">var test_value = "\u2014";</script>
{% endcompress %}
"""
out = '<script type="text/javascript" src="/static/CACHE/js/be9e078b5ca7.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/a830bddd3636.js"></script>'
self.assertEqual(out, render(template, self.context))
def test_compress_tag_with_illegal_arguments(self):
@@ -152,7 +152,7 @@ class TemplatetagTestCase(TestCase):
<script type="text/javascript">var tmpl="{% templatetag openblock %} if x == 3 %}x IS 3{% templatetag openblock %} endif %}"</script>
{% endaddtoblock %}{% render_block "js" postprocessor "compressor.contrib.sekizai.compress" %}
"""
out = '<script type="text/javascript" src="/static/CACHE/js/e9fce10d884d.js"></script>'
out = '<script type="text/javascript" src="/static/CACHE/js/74e008a57789.js"></script>'
self.assertEqual(out, render(template, self.context, SekizaiContext))
@@ -180,7 +180,7 @@ class PrecompilerTemplatetagTestCase(TestCase):
template = """{% load compress %}{% compress js %}
<script type="text/coffeescript"># this is a comment.</script>
{% endcompress %}"""
out = script(src="/static/CACHE/js/e920d58f166d.js")
out = script(src="/static/CACHE/js/82d254e4462a.js")
self.assertEqual(out, render(template, self.context))
def test_compress_coffeescript_tag_and_javascript_tag(self):
@@ -188,7 +188,7 @@ class PrecompilerTemplatetagTestCase(TestCase):
<script type="text/coffeescript"># this is a comment.</script>
<script type="text/javascript"># this too is a comment.</script>
{% endcompress %}"""
out = script(src="/static/CACHE/js/ef6b32a54575.js")
out = script(src="/static/CACHE/js/07bc3c26db9a.js")
self.assertEqual(out, render(template, self.context))
@override_settings(COMPRESS_ENABLED=False)