# Path: textplusstuff/datastructures.py
# class TextPlusStuff(object):
# 
#     def __init__(self, raw_text, field=None):
#         raw_text = raw_text or ""
#         if not isinstance(raw_text, str):
#             raise UnicodeError(
#                 (
#                     "TextPlusStuff can only be initialized with either "
#                     "unicode or UTF-8 strings."
#                 )
#             )
#         else:
#             raw_text_processed = force_text(raw_text, errors='replace')
#         self.raw_text = raw_text_processed
#         # Initialize lexer
#         lexer = TextPlusStuffLexer(raw_val=raw_text_processed)
#         # Use the lexer to create tokens
#         tokens = lexer.tokenize()
#         # Pass tokens to parser and parse
#         self.nodelist = TextPlusStuffParser(tokens=tokens).parse()
# 
#     def render(self, render_markdown_as, **kwargs):
#         """
#         Renders a TextPlusStuffField
#         `render_markdown_as`: The format that markdown-flavored text should
#         be transformed in. Options: `html`, `markdown`, `plain_text`
#         """
#         final_output = ""
#         include_content_nodes = kwargs.pop('include_content_nodes', True)
#         extra_context = kwargs.pop('extra_context', None)
#         for node in self.nodelist:
#             if isinstance(node, MarkdownFlavoredTextNode):
#                 final_output += node.render(render_as=render_markdown_as)
#             elif isinstance(node, ModelStuffNode):
#                 if include_content_nodes is False:
#                     pass
#                 else:
#                     final_output += node.render(extra_context=extra_context)
#         return final_output
# 
#     def as_html(self, **kwargs):
#         """
#         Renders a TextPlusStuffField as HTML.
#         Optional keyword arguments:
#         * `include_content_nodes`: Boolean signifying whether or not to render
#                                    content nodes (i.e. ModelStuff tokens).
#                                    Defaults to `True`.
#         """
#         return mark_safe(
#             self.render(
#                 'html',
#                 include_content_nodes=kwargs.pop(
#                     'include_content_nodes', True
#                 ),
#                 extra_context=kwargs.pop('extra_context', None)
#             )
#         )
# 
#     def as_json(self, **kwargs):
#         """
#         Renders a TextPlusStuffField as a JSON object.
# 
#         * `render_markdown_as`: The format that markdown-flavored text should
#         be transformed in. Options: `html` (default), `markdown`, `plain_text`.
#         """
#         final_output_as_html = ""
#         final_output_as_markdown = ""
#         include_content_nodes = kwargs.pop('include_content_nodes', True)
#         extra_context = kwargs.pop('extra_context', None)
#         convert_to_json_string = kwargs.pop('convert_to_json_string', False)
#         model_stuff_node_counter = 0
#         model_stuff_node_context_list = []
#         for node in self.nodelist:
#             if isinstance(node, MarkdownFlavoredTextNode):
#                 final_output_as_html += node.render(render_as='html')
#                 final_output_as_markdown += node.render(render_as='markdown')
#             elif isinstance(node, ModelStuffNode):
#                 if include_content_nodes is True:
#                     final_output_as_markdown += "{{{{ NODE__{index} }}}}"\
#                         .format(
#                             index=model_stuff_node_counter
#                         )
#                     final_output_as_html += (
#                         '<span data-textplusstuff-contentnode-arrayindex='
#                         '"{index}"></span>'
#                     ).format(index=model_stuff_node_counter)
#                     model_stuff_node_context_list.append({
#                         'model': '{}:{}'.format(
#                             node.node_mapping.get('content_type__app_label'),
#                             node.node_mapping.get('content_type__model')
#                         ),
#                         'rendition': node.get_rendition().short_name,
#                         'context': node.get_node_context(
#                             extra_context=extra_context
#                         )
#                     })
#                     model_stuff_node_counter += 1
#         dict_to_return = {
#             'text_as_markdown': final_output_as_markdown,
#             'text_as_html': final_output_as_html,
#             'content_nodes': model_stuff_node_context_list
#         }
# 
#         to_return = dict_to_return
#         if convert_to_json_string is True:
#             to_return = json.dumps(dict_to_return)
# 
#         return to_return
# 
#     def as_plaintext(self, **kwargs):
#         """
#         Renders a TextPlusStuffField as plain text (all markdown
#         formatting removed).
# 
#         Content nodes (i.e. ModelStuff tokens) will not be rendered.
#         """
#         return self.render(
#             'plain_text',
#             include_content_nodes=False
#         )
# 
#     def as_markdown(self, **kwargs):
#         """
#         Renders a TextPlusStuffField as markdown.
# 
#         Content nodes (i.e. ModelStuff tokens) will not be rendered.
#         """
#         return self.render(
#             'markdown',
#             include_content_nodes=False
#         )


import copy
from rest_framework import VERSION as REST_FRAMEWORK_VERSION
from rest_framework.serializers import CharField
from .datastructures import TextPlusStuff
        extra_context.pop('view', None)
        extra_context.pop('request', None)
        extra_context.pop('format', None)
        payload.update({
            'extra_context': extra_context
        })
        return payload


class TextPlusStuffFieldSerializer(CharField):
    """
    Return a dictionary of all available permutations of a TextPlusStuffField

    Example:
    {
        'raw_text': <Raw value of the field>,
        'as_plaintext': <As plaintext, no tokens rendered>,
        'as_markdown': <As markdown, no tokens rendered>,
        'as_html': <As HTML markup with tokens rendered>,
        'as_html_no_tokens': <As HTML markup no tokens rendered>,
    }
    """

    read_only = True

    def to_native(self, value):
        """For djangorestframework>=2.4.x"""
        return self.to_representation(value)

    def to_representation(self, value):

# Path: textplusstuff/datastructures.py
# class TextPlusStuff(object):
# 
#     def __init__(self, raw_text, field=None):
#         raw_text = raw_text or ""
#         if not isinstance(raw_text, str):
#             raise UnicodeError(
#                 (
#                     "TextPlusStuff can only be initialized with either "
#                     "unicode or UTF-8 strings."
#                 )
#             )
#         else:
#             raw_text_processed = force_text(raw_text, errors='replace')
#         self.raw_text = raw_text_processed
#         # Initialize lexer
#         lexer = TextPlusStuffLexer(raw_val=raw_text_processed)
#         # Use the lexer to create tokens
#         tokens = lexer.tokenize()
#         # Pass tokens to parser and parse
#         self.nodelist = TextPlusStuffParser(tokens=tokens).parse()
# 
#     def render(self, render_markdown_as, **kwargs):
#         """
#         Renders a TextPlusStuffField
#         `render_markdown_as`: The format that markdown-flavored text should
#         be transformed in. Options: `html`, `markdown`, `plain_text`
#         """
#         final_output = ""
#         include_content_nodes = kwargs.pop('include_content_nodes', True)
#         extra_context = kwargs.pop('extra_context', None)
#         for node in self.nodelist:
#             if isinstance(node, MarkdownFlavoredTextNode):
#                 final_output += node.render(render_as=render_markdown_as)
#             elif isinstance(node, ModelStuffNode):
#                 if include_content_nodes is False:
#                     pass
#                 else:
#                     final_output += node.render(extra_context=extra_context)
#         return final_output
# 
#     def as_html(self, **kwargs):
#         """
#         Renders a TextPlusStuffField as HTML.
#         Optional keyword arguments:
#         * `include_content_nodes`: Boolean signifying whether or not to render
#                                    content nodes (i.e. ModelStuff tokens).
#                                    Defaults to `True`.
#         """
#         return mark_safe(
#             self.render(
#                 'html',
#                 include_content_nodes=kwargs.pop(
#                     'include_content_nodes', True
#                 ),
#                 extra_context=kwargs.pop('extra_context', None)
#             )
#         )
# 
#     def as_json(self, **kwargs):
#         """
#         Renders a TextPlusStuffField as a JSON object.
# 
#         * `render_markdown_as`: The format that markdown-flavored text should
#         be transformed in. Options: `html` (default), `markdown`, `plain_text`.
#         """
#         final_output_as_html = ""
#         final_output_as_markdown = ""
#         include_content_nodes = kwargs.pop('include_content_nodes', True)
#         extra_context = kwargs.pop('extra_context', None)
#         convert_to_json_string = kwargs.pop('convert_to_json_string', False)
#         model_stuff_node_counter = 0
#         model_stuff_node_context_list = []
#         for node in self.nodelist:
#             if isinstance(node, MarkdownFlavoredTextNode):
#                 final_output_as_html += node.render(render_as='html')
#                 final_output_as_markdown += node.render(render_as='markdown')
#             elif isinstance(node, ModelStuffNode):
#                 if include_content_nodes is True:
#                     final_output_as_markdown += "{{{{ NODE__{index} }}}}"\
#                         .format(
#                             index=model_stuff_node_counter
#                         )
#                     final_output_as_html += (
#                         '<span data-textplusstuff-contentnode-arrayindex='
#                         '"{index}"></span>'
#                     ).format(index=model_stuff_node_counter)
#                     model_stuff_node_context_list.append({
#                         'model': '{}:{}'.format(
#                             node.node_mapping.get('content_type__app_label'),
#                             node.node_mapping.get('content_type__model')
#                         ),
#                         'rendition': node.get_rendition().short_name,
#                         'context': node.get_node_context(
#                             extra_context=extra_context
#                         )
#                     })
#                     model_stuff_node_counter += 1
#         dict_to_return = {
#             'text_as_markdown': final_output_as_markdown,
#             'text_as_html': final_output_as_html,
#             'content_nodes': model_stuff_node_context_list
#         }
# 
#         to_return = dict_to_return
#         if convert_to_json_string is True:
#             to_return = json.dumps(dict_to_return)
# 
#         return to_return
# 
#     def as_plaintext(self, **kwargs):
#         """
#         Renders a TextPlusStuffField as plain text (all markdown
#         formatting removed).
# 
#         Content nodes (i.e. ModelStuff tokens) will not be rendered.
#         """
#         return self.render(
#             'plain_text',
#             include_content_nodes=False
#         )
# 
#     def as_markdown(self, **kwargs):
#         """
#         Renders a TextPlusStuffField as markdown.
# 
#         Content nodes (i.e. ModelStuff tokens) will not be rendered.
#         """
#         return self.render(
#             'markdown',
#             include_content_nodes=False
#         )


# Path: textplusstuff/serializers.py
import copy
from rest_framework import VERSION as REST_FRAMEWORK_VERSION
from rest_framework.serializers import CharField
from .datastructures import TextPlusStuff

        extra_context.pop('view', None)
        extra_context.pop('request', None)
        extra_context.pop('format', None)
        payload.update({
            'extra_context': extra_context
        })
        return payload


class TextPlusStuffFieldSerializer(CharField):
    """
    Return a dictionary of all available permutations of a TextPlusStuffField

    Example:
    {
        'raw_text': <Raw value of the field>,
        'as_plaintext': <As plaintext, no tokens rendered>,
        'as_markdown': <As markdown, no tokens rendered>,
        'as_html': <As HTML markup with tokens rendered>,
        'as_html_no_tokens': <As HTML markup no tokens rendered>,
    }
    """

    read_only = True

    def to_native(self, value):
        """For djangorestframework>=2.4.x"""
        return self.to_representation(value)

    def to_representation(self, value):

        if not isinstance(value, TextPlusStuff):