Skip to content

Commit

Permalink
update docs for 2.1 release, change default indent from tab to 4 spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
bckohan committed Nov 20, 2023
1 parent 5b379fa commit da51253
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 26 deletions.
4 changes: 4 additions & 0 deletions doc/source/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ single template, if the ``dest`` parameter is not an existing directory, it will
the full path including the file name where the template will be rendered. When rendering in batch
mode, ``dest`` will be treated as a directory and created if it does not exist.

The ``dest`` parameter may include template variables that will be replaced with the value of the
variable in the context. For example, if ``dest`` is ``'js/{{ app_name }}.js'`` and the context
contains ``{'app_name': 'my_app'}`` then the template will be rendered to ``js/my_app.js``.

``context``
~~~~~~~~~~~

Expand Down
6 changes: 6 additions & 0 deletions doc/source/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ transpilers
.. autofunction:: to_js_datetime
.. autoclass:: CodeWriter
.. autoclass:: Transpiler
.. autoproperty:: Transpiler.context


.. _transpilers_defines_to_js:
Expand All @@ -131,6 +132,7 @@ transpilers.defines_to_js
.. automodule:: render_static.transpilers.defines_to_js

.. autoclass:: DefaultDefineTranspiler
.. autoproperty:: DefaultDefineTranspiler.context


.. _transpilers_urls_to_js:
Expand All @@ -141,8 +143,11 @@ transpilers.urls_to_js
.. automodule:: render_static.transpilers.urls_to_js

.. autoclass:: URLTreeVisitor
.. autoproperty:: URLTreeVisitor.context
.. autoclass:: SimpleURLWriter
.. autoproperty:: SimpleURLWriter.context
.. autoclass:: ClassURLWriter
.. autoproperty:: ClassURLWriter.context
.. autoclass:: Substitute
.. autofunction:: normalize_ns
.. autofunction:: build_tree
Expand All @@ -158,6 +163,7 @@ transpilers.enums_to_js
.. autoclass:: UnrecognizedBehavior
.. autoclass:: EnumTranspiler
.. autoclass:: EnumClassWriter
.. autoproperty:: EnumClassWriter.context


.. _context:
Expand Down
198 changes: 187 additions & 11 deletions doc/source/templatetags.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,25 @@ The generated source would look like:
parent classes and add them to the JavaScript.


Overrides
*********

The ``DefaultDefineTranspiler`` supports the :ref:`override` block. The context available to
override blocks is detailed here:
:py:attr:`render_static.transpilers.defines_to_js.DefaultDefineTranspiler.context`. More code
can be added to define variables or specific defines can be overridden by using their python
path:

.. code-block:: js+django

{% defines_to_js defines='myapp' %}

{% override 'myapp.defines.TestDefines.DEFINE1' %}
"OVERRIDE"
{% endoverride %}

{% enddefines_to_js %}

.. _urls_to_js:

``urls_to_js``
Expand Down Expand Up @@ -265,15 +284,36 @@ Placeholders are the price paid for that reliability. Common default placeholder
after all registered placeholders fail, and all of Django's native path converters are
supported. This should allow most urls to work out of the box.

Overrides
*********

Both the ``ClassURLWriter`` and ``SimpleURLWriter`` transpilers support the :ref:`override`
block. The contexts available to override blocks for each transpiler are detailed here:

- :py:attr:`render_static.transpilers.urls_to_js.SimpleURLWriter.context`
- :py:attr:`render_static.transpilers.urls_to_js.ClassURLWriter.context`

Any function on ``ClassURLWriter`` including the constructor can be overridden and both
transpilers allow adding to the class or object and overriding the reversal code for
specific url names. For instance:

.. code-block:: js+django

{% urls_to_js transpiler='render_static.SimpleURLWriter' %}

{% override 'namespace:path_name' %}
return "/an/overridden/path";
{% endoverride %}

{% endurls_to_js %}

`ClassURLWriter` (default)
**************************

A transpiler class that produces ES6 JavaScript class is now included. As of version 2 This
class is used by default. It is the preferred transpiler for larger, more complex URL trees
because it minifies better than the ``SimpleURLWriter`` and it handles default kwargs
appropriately. **The** ``ClassURLWriter`` **is guaranteed to produce output identical to Django's
reverse function**. If it does not please report a bug. To use the class writer:
class is used by default. **The** ``ClassURLWriter`` **is guaranteed to produce output
identical to Django's reverse function**. If it does not please report a bug. To use the
class writer:

.. code-block:: htmldjango
Expand Down Expand Up @@ -532,13 +572,14 @@ like this:
}
static get(value) {
switch(value) {
case "R":
return Color.RED;
case "G":
return Color.GREEN;
case "B":
return Color.BLUE;
if (value instanceof this) {
return value;
}
for (const en of this) {
if (en.value === value) {
return en;
}
}
throw new TypeError(`No Color enumeration maps to value ${value}`);
}
Expand All @@ -556,3 +597,138 @@ We can now use our enumeration like so:
for (const color of Color) {
console.log(color);
}
Overrides
*********

You may add additional code to the class or :ref:`override` the following functions:

- constructor
- toString
- get
- ciCompare
- [Symbol.iterator]

See :py:attr:`render_static.transpilers.enums_to_js.EnumClassWriter.context` for the
context made available by the transpiler to override blocks.

.. _override:

``override``
~~~~~~~~~~~~

All of the transpilation tags accept child override blocks to override default transpilation
of functions or objects or be used to add additional code to an object block or class. For
example, if we wanted to override the default transpilation of the Color class above to allow
instantiation off a cmyk value we could do so by adapting the get function and adding a new
static utility function called cmykToRgb. We would do so like this:


.. code:: js+django

{% enums_to_js enums="examples.models.ExampleModel.Color" %}

{# to override a function we must pass its name as the argument #}
{% override 'get' %}
static get(value) {
if (Array.isArray(value) && value.length === 4) {
value = Color.cmykToRgb(...value);
}

if (Array.isArray(value) && value.length === 3) {
for (const en of this) {
let i = 0;
for (; i < 3; i++) {
if (en.rgb[i] !== value[i]) break;
}
if (i === 3) return en;
}
}
{{ default_impl }}
}
{% endoverride %}

{# additions do not require a name argument #}
{% override %}
static cmykToRgb(c, m, y, k) {

let r = 255 * (1 - c / 100) * (1 - k / 100);
let g = 255 * (1 - m / 100) * (1 - k / 100);
let b = 255 * (1 - y / 100) * (1 - k / 100);

return [Math.round(r), Math.round(g), Math.round(b)]
}
{% endoverride %}
{% endenums_to_js %}

When a function is overridden, the default implementation is available in the template context
as the ``default_impl`` variable. This allows you to add the default implementation from
code to your override. The context available to an override block varies depending on the
transpiler. See the individual tag sections for details.

The above example will generate code that looks like this:

.. code:: javascript
class Color {
static RED = new Color("R", "RED", "Red", [1, 0, 0], "ff0000");
static GREEN = new Color("G", "GREEN", "Green", [0, 1, 0], "00ff00");
static BLUE = new Color("B", "BLUE", "Blue", [0, 0, 1], "0000ff");
constructor (value, name, label, rgb, hex) {
this.value = value;
this.name = name;
this.label = label;
this.rgb = rgb;
this.hex = hex;
}
toString() {
return this.value;
}
static get(value) {
if (Array.isArray(value) && value.length === 4) {
value = Color.cmykToRgb(...value);
}
if (Array.isArray(value) && value.length === 3) {
for (const en of this) {
let i = 0;
for (; i < 3; i++) {
if (en.rgb[i] !== value[i]) break;
}
if (i === 3) return en;
}
}
if (value instanceof this) {
return value;
}
for (const en of this) {
if (en.value === value) {
return en;
}
}
throw new TypeError(`No Color enumeration maps to value ${value}`);
}
static [Symbol.iterator]() {
return [Color.RED, Color.GREEN, Color.BLUE][Symbol.iterator]();
}
static cmykToRgb(c, m, y, k) {
let r = (1 - c / 100) * (1 - k / 100);
let g = (1 - m / 100) * (1 - k / 100);
let b = (1 - y / 100) * (1 - k / 100);
return [Math.round(r), Math.round(g), Math.round(b)]
}
}
.. note::

The Jinja2 tags do not currently support overrides.
65 changes: 65 additions & 0 deletions render_static/tests/examples_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.test import override_settings
from django.urls import reverse
from render_static.tests.js_tests import (
GLOBAL_STATIC_DIR,
EnumComparator,
StructureDiff,
URLJavascriptMixin,
Expand Down Expand Up @@ -135,6 +136,70 @@ def test_readme_enums(self):
"'Blue',\n rgb: [ 0, 0, 1 ],\n hex: '0000ff'\n}"
)

@override_settings(
STATIC_TEMPLATES={
'ENGINES': [{
'BACKEND': 'render_static.backends.StaticDjangoTemplates',
'OPTIONS': {
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'color.js': """
{% enums_to_js enums="render_static.tests.examples.models.ExampleModel.Color" %}
{# to override a function we must pass its name as the argument #}
{% override 'get' %}
static get(value) {
if (Array.isArray(value) && value.length === 4) {
value = Color.cmykToRgb(...value);
}
if (Array.isArray(value) && value.length === 3) {
for (const en of this) {
let i = 0;
for (; i < 3; i++) {
if (en.rgb[i] !== value[i]) break;
}
if (i === 3) return en;
}
}
{{ default_impl }}
}
{% endoverride %}
{# additions do not require a name argument #}
{% override %}
static cmykToRgb(c, m, y, k) {
let r = (1 - c / 100) * (1 - k / 100);
let g = (1 - m / 100) * (1 - k / 100);
let b = (1 - y / 100) * (1 - k / 100);
return [Math.round(r), Math.round(g), Math.round(b)]
}
{% endoverride %}
{% endenums_to_js %}
console.log(Color.get([0, 100, 100, 0]).label);
"""
}),
'render_static.loaders.StaticAppDirectoriesBatchLoader'
]
},
}]
}
)
class TestEnumOverrideExample(BaseTestCase):

to_remove = [
GLOBAL_STATIC_DIR
]

def tearDown(self):
pass

def test_override_example(self):
call_command('renderstatic', 'color.js')
result = run_js_file(GLOBAL_STATIC_DIR / 'color.js')
self.assertEqual(result, 'Red')


@override_settings(
ROOT_URLCONF='render_static.tests.examples.urls',
Expand Down
12 changes: 9 additions & 3 deletions render_static/transpilers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class CodeWriter:
rendered_: str
level_: int = 0
prefix_: str = ''
indent_: str = '\t'
indent_: str = ' '*4
nl_: str = '\n'

def __init__(
Expand Down Expand Up @@ -230,8 +230,14 @@ def parents(self):

@property
def context(self):
"""A local template render context passed to overrides"""
return {}
"""
The base template render context passed to overrides. Includes:
- **transpiler**: The transpiler instance
"""
return {
'transpiler': self
}

def __init__(
self,
Expand Down
6 changes: 5 additions & 1 deletion render_static/transpilers/defines_to_js.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ def include_target(self, target: ResolvedTranspilerTarget):
@property
def context(self) -> Dict[str, Any]:
"""
The context passed to override blocks.
The template render context passed to overrides. In addition to
:attr:`render_static.transpilers.Transpiler.context`.
This includes:
- **const_name**: The name of the const variable
"""
return {
**Transpiler.context.fget(self), # type: ignore
Expand Down
Loading

0 comments on commit da51253

Please sign in to comment.