def format_property_details(self,
                                prop_name,
                                prop_type,
                                prop_description,
                                enum,
                                enum_details,
                                supplemental_details,
                                parent_prop_info,
                                profile=None):
        """Generate a formatted table of enum information for inclusion in Property details."""

        contents = []

        parent_version = parent_prop_info.get('versionAdded')
        if parent_version:
            parent_version = self.format_version(parent_version)

        # Are we in profile mode? If so, consult the profile passed in for this property.
        # For Action Parameters, look for ParameterValues/RecommendedValues; for
        # Property enums, look for MinSupportValues/RecommendedValues.
        profile_mode = self.config.get('profile_mode')
        if profile_mode:
            if profile is None:
                profile = {}

            profile_values = profile.get('Values', [])
            profile_min_support_values = profile.get(
                'MinSupportValues', [])  # No longer a valid name?
            profile_parameter_values = profile.get('ParameterValues', [])
            profile_recommended_values = profile.get('RecommendedValues', [])

            # profile_all_values is not used. What were we going for here?
            profile_all_values = (profile_values + profile_min_support_values +
                                  profile_parameter_values +
                                  profile_recommended_values)

            # In subset mode, an action parameter with no Values (property) or ParameterValues (Action)
            # means all values are supported.
            # Otherwise, Values/ParameterValues specifies the set that should be listed.
            if profile_mode == 'subset':
                if len(profile_values):
                    enum = [x for x in enum if x in profile_values]
                elif len(profile_parameter_values):
                    enum = [x for x in enum if x in profile_parameter_values]

        if prop_description:
            contents.append(
                self.formatter.para(
                    self.escape_for_markdown(
                        prop_description, self.config.get('escape_chars',
                                                          []))))

        if isinstance(prop_type, list):
            prop_type = ', '.join(prop_type)

        if supplemental_details:
            contents.append('\n' + supplemental_details + '\n')

        enum_translations = parent_prop_info.get('enumTranslations', {})

        if enum_details:
            if profile_mode and profile_mode != 'subset':
                contents.append('| ' + prop_type + ' | ' + _('Description') +
                                ' | ' + _('Profile Specifies') + ' |')
                contents.append('| --- | --- | --- |')
            else:
                contents.append('| ' + prop_type + ' | ' + _('Description') +
                                ' |')
                contents.append('| --- | --- |')
            enum.sort(key=str.lower)
            for enum_item in enum:
                enum_name = enum_item
                enum_translation = enum_translations.get(enum_item)
                version = version_depr = deprecated_descr = None
                version_display = None
                if parent_prop_info.get('enumVersionAdded'):
                    version_added = parent_prop_info.get(
                        'enumVersionAdded').get(enum_name)
                    if version_added:
                        version = self.format_version(version_added)
                if parent_prop_info.get('enumVersionDeprecated'):
                    version_deprecated = parent_prop_info.get(
                        'enumVersionDeprecated').get(enum_name)
                    if version_deprecated:
                        version_depr = self.format_version(version_deprecated)
                if parent_prop_info.get('enumDeprecated'):
                    deprecated_descr = parent_prop_info.get(
                        'enumDeprecated').get(enum_name)

                if enum_translation:
                    enum_name += ' (' + enum_translation + ')'

                if version:
                    if not parent_version or DocGenUtilities.compare_versions(
                            version, parent_version) > 0:
                        version_display = self.truncate_version(version,
                                                                2) + '+'

                if version_display:
                    if version_depr:
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        enum_name += ' ' + self.formatter.italic(
                            _('(v%(version_number)s, deprecated v%(deprecated_version)s)'
                              ) % {
                                  'version_number': version_display,
                                  'deprecated_version': deprecated_display
                              })
                        if deprecated_descr:
                            deprecated_descr = (_(
                                'Deprecated in v%(version_number)s and later. %(explanation)s'
                            ) % {
                                'version_number': deprecated_display,
                                'explanation': deprecated_descr
                            })
                    else:
                        enum_name += ' ' + self.formatter.italic(
                            _('(v%(version_number)s)') %
                            {'version_number': version_display})
                elif version_depr:
                    deprecated_display = self.truncate_version(version_depr, 2)
                    enum_name += ' ' + self.formatter.italic(
                        _('(deprecated v%(version_number)s)') %
                        {'version_number': deprecated_display})
                    if deprecated_descr:
                        deprecated_descr = (_(
                            'Deprecated in v%(version_number)s and later. %(explanation)s'
                        ) % {
                            'version_number': deprecated_display,
                            'explanation': deprecated_descr
                        })

                descr = enum_details.get(enum_item, '')
                if deprecated_descr:
                    if descr:
                        descr += ' ' + self.formatter.italic(deprecated_descr)
                    else:
                        descr = self.formatter.italic(deprecated_descr)

                if profile_mode and profile_mode != 'subset':
                    profile_spec = ''
                    # Note: don't wrap the following strings for trnaslation; self.text_map handles that.
                    if enum_item in profile_values:
                        profile_spec = 'Mandatory'
                    elif enum_item in profile_min_support_values:
                        profile_spec = 'Mandatory'
                    elif enum_item in profile_parameter_values:
                        profile_spec = 'Mandatory'
                    elif enum_item in profile_recommended_values:
                        profile_spec = 'Recommended'
                    contents.append('| ' + enum_name + ' | ' + descr + ' | ' +
                                    self.text_map(profile_spec) + ' |')
                else:
                    contents.append('| ' + enum_name + ' | ' + descr + ' |')

        elif enum:
            if profile_mode and profile_mode != 'subset':
                contents.append('| ' + prop_type + ' | ' +
                                _('Profile Specifies') + ' |')
                contents.append('| --- | --- |')
            else:
                contents.append('| ' + prop_type + ' |')
                contents.append('| --- |')
            for enum_item in enum:
                enum_name = enum_item
                version = version_depr = deprecated_descr = None
                version_display = None

                if parent_prop_info.get('enumVersionAdded'):
                    version_added = parent_prop_info.get(
                        'enumVersionAdded').get(enum_name)
                    if version_added:
                        version = self.format_version(version_added)

                if parent_prop_info('enumVersionDeprecated'):
                    version_deprecated = parent_prop_info.get(
                        'enumVersionDeprecated').get(enum_name)
                    if version_deprecated:
                        version_depr = self.format_version(version_deprecated)

                if parent_prop_info.get('enumDeprecated'):
                    deprecated_descr = parent_prop_info.get(
                        'enumDeprecated').get(enum_name)

                if version:
                    if not parent_version or DocGenUtilities.compare_versions(
                            version, parent_version) > 0:
                        version_text = html.escape(version, False)
                        version_display = self.truncate_version(
                            version_text, 2) + '+'

                if version_display:
                    if version_depr:
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        if deprecated_descr:
                            enum_name += ' ' + self.formatter.italic(
                                _('(v%(version_number)s, deprecated v%(deprecated_version)s. %(explanation)s'
                                  ) % {
                                      'version_number': version_display,
                                      'deprecated_version': deprecated_display,
                                      'explanation': deprecated_descr
                                  })
                        else:
                            enum_name += ' ' + self.formatter.italic(
                                _('(v%(version_number)s, deprecated v%(deprecated_version)s)'
                                  ) % {
                                      'version_number': version_display,
                                      'deprecated_version': deprecated_display
                                  })

                    else:
                        enum_name += ' ' + self.formatter.italic(
                            _('(v%(version_number)s)') %
                            {'version_number': version_display})
                else:
                    if version_depr:
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        if deprecated_descr:
                            enum_name += ' ' + self.formatter.italic(
                                _('Deprecated in v%(deprecated_version)s and later. %(explanation)s'
                                  ) % {
                                      'deprecated_version': deprecated_display,
                                      'explanation': deprecated_descr
                                  })
                        else:
                            enum_name += ' ' + self.formatter.italic(
                                _('(deprecated in v%(deprecated_version)s and later.)'
                                  ) %
                                {'deprecated_version': deprecated_display})

                if profile_mode and profile_mode != 'subset':
                    profile_spec = ''
                    # Note: don't wrap the following strings for trnaslation; self.text_map handles that.
                    if enum_name in profile_values:
                        profile_spec = 'Mandatory'
                    elif enum_name in profile_min_support_values:
                        profile_spec = 'Mandatory'
                    elif enum_name in profile_parameter_values:
                        profile_spec = 'Mandatory'
                    elif enum_name in profile_recommended_values:
                        profile_spec = 'Recommended'

                    contents.append('| ' + enum_name + ' | ' +
                                    self.text_map(profile_spec) + ' |')
                else:
                    contents.append('| ' + enum_name + ' | ')

        caption = self.formatter.add_table_caption(
            _("%(prop_name)s property values") % {'prop_name': prop_name})
        preamble = self.formatter.add_table_reference(
            _("The defined property values are listed in "))

        return preamble + '\n'.join(contents) + '\n' + caption
Example #2
0
    def format_property_row(self,
                            schema_ref,
                            prop_name,
                            prop_info,
                            prop_path=[],
                            in_array=False):
        """Format information for a single property.

        Returns an object with 'row', 'details', 'action_details', and 'profile_conditional_details':

        'row': content for the main table being generated.
        'details': content for the Property Details section.
        'action_details': content for the Actions section.
        'profile_conditional_details': populated only in profile_mode, formatted conditional details

        This may include embedded objects with their own properties.
        """

        traverser = self.traverser
        formatted = []  # The row itself

        current_depth = len(prop_path)

        if in_array:
            current_depth = current_depth - 1

        # strip_top_object is used for fragments, to allow output of just the properties
        # without the enclosing object:
        if self.config.get('strip_top_object') and current_depth > 0:
            indentation_string = ' ' * 6 * (current_depth - 1)
        else:
            indentation_string = ' ' * 6 * current_depth

        # If prop_path starts with Actions and is more than 1 deep, we are outputting for an Action Details
        # section and should dial back the indentation by one level.
        if len(prop_path) > 1 and prop_path[0] == 'Actions':
            indentation_string = ' ' * 6 * (current_depth - 1)

        collapse_array = False  # Should we collapse a list description into one row? For lists of simple types
        has_enum = False

        if current_depth < self.current_depth:
            for i in range(current_depth, self.current_depth):
                if i in self.current_version:
                    del self.current_version[i]
        self.current_depth = current_depth
        parent_depth = current_depth - 1

        if isinstance(prop_info, list):
            meta = prop_info[0].get('_doc_generator_meta')
            has_enum = 'enum' in prop_info[0]
        elif isinstance(prop_info, dict):
            meta = prop_info.get('_doc_generator_meta')
            has_enum = 'enum' in prop_info
        if not meta:
            meta = {}

        # We want to modify a local copy of meta, deleting redundant version info
        meta = copy.deepcopy(meta)

        name_and_version = self.formatter.bold(html.escape(prop_name, False))
        deprecated_descr = None

        version = meta.get('version')
        self.current_version[current_depth] = version

        # Don't display version if there is a parent version and this is not newer:
        if self.current_version.get(parent_depth) and version:
            if DocGenUtilities.compare_versions(
                    version, self.current_version.get(parent_depth)) <= 0:
                del meta['version']

        if meta.get('version', '1.0.0') != '1.0.0':
            version_text = html.escape(meta['version'], False)
            version_display = self.truncate_version(version_text, 2) + '+'
            if 'version_deprecated' in meta:
                version_depr = html.escape(meta['version_deprecated'], False)
                deprecated_display = self.truncate_version(version_depr, 2)
                name_and_version += ' ' + self.formatter.italic(
                    '(v' + version_display + ', deprecated v' +
                    deprecated_display + ')')
                deprecated_descr = html.escape(
                    "Deprecated v" + deprecated_display + '+. ' +
                    meta['version_deprecated_explanation'], False)
            else:
                name_and_version += ' ' + self.formatter.italic(
                    '(v' + version_display + ')')
        elif 'version_deprecated' in meta:
            version_depr = html.escape(meta['version_deprecated'], False)
            deprecated_display = self.truncate_version(version_depr, 2)
            name_and_version += ' ' + self.formatter.italic(
                '(deprecated v' + deprecated_display + ')')
            deprecated_descr = html.escape(
                "Deprecated v" + deprecated_display + '+. ' +
                meta['version_deprecated_explanation'], False)

        formatted_details = self.parse_property_info(schema_ref, prop_name,
                                                     prop_info, prop_path,
                                                     meta.get('within_action'))

        if formatted_details.get('promote_me'):
            return ({
                'row': '\n'.join(formatted_details['item_description']),
                'details': formatted_details['prop_details'],
                'action_details': formatted_details.get('action_details')
            })

        if self.config.get('strip_top_object') and current_depth == 0:
            # In this case, we're done for this bit of documentation, and we just want the properties of this object.
            formatted.append('\n'.join(
                formatted_details['object_description']))
            return ({
                'row':
                '\n'.join(formatted),
                'details':
                formatted_details['prop_details'],
                'action_details':
                formatted_details.get('action_details'),
                'profile_conditional_details':
                formatted_details.get('profile_conditional_details')
            })

        # Eliminate dups in these these properties and join with a delimiter:
        props = {
            'prop_type': self.separators['inline'],
            'descr': self.separators['linebreak'],
            'object_description': '\n',
            'item_description': '\n'
        }

        for property_name, delim in props.items():
            if isinstance(formatted_details[property_name], list):
                property_values = []
                self.append_unique_values(formatted_details[property_name],
                                          property_values)
                formatted_details[property_name] = delim.join(property_values)

        if formatted_details['prop_is_object'] and not in_array:
            if formatted_details['object_description'] == '':
                name_and_version += ' { }'
            else:
                name_and_version += ' {'

        if formatted_details['prop_is_array']:
            if formatted_details['item_description'] == '':
                if formatted_details['array_of_objects']:
                    name_and_version += ' [ { } ]'
                else:
                    name_and_version += ' [ ] '
            else:
                if formatted_details['array_of_objects']:
                    name_and_version += ' [ {'
                else:
                    collapse_array = True
                    name_and_version += ' [ ] '
        elif in_array:
            if formatted_details['prop_is_object']:
                name_and_version += ' [ { } ]'
            else:
                name_and_version += ' [ ] '

        name_and_version = '<nobr>' + name_and_version + '</nobr>'

        if formatted_details['descr'] is None:
            formatted_details['descr'] = ''

        formatted_details['descr'] = self.formatter.markdown_to_html(
            html.escape(formatted_details['descr'], False), no_para=True)

        if formatted_details['add_link_text']:
            if formatted_details['descr']:
                formatted_details['descr'] += ' '
            formatted_details['descr'] += formatted_details['add_link_text']

        # Append reference info to descriptions, if appropriate:
        if not formatted_details.get('fulldescription_override'):
            # If there are prop_details (enum details), add a note to the description:
            if formatted_details[
                    'has_direct_prop_details'] and not formatted_details[
                        'has_action_details']:
                if has_enum:
                    anchor = schema_ref + '|details|' + prop_name
                    text_descr = 'See <a href="#' + anchor + '">' + prop_name + '</a> in Property Details, below, for the possible values of this property.'
                else:
                    text_descr = 'See Property Details, below, for more information about this property.'

                if formatted_details['descr']:
                    formatted_details[
                        'descr'] += '<br>' + self.formatter.italic(text_descr)
                else:
                    formatted_details['descr'] = self.formatter.italic(
                        text_descr)

            # If this is an Action with details, add a note to the description:
            if formatted_details['has_action_details']:
                anchor = schema_ref + '|action_details|' + prop_name
                text_descr = 'For more information, see the <a href="#' + anchor + '">Action Details</a> section below.'
                formatted_details['descr'] += '<br>' + self.formatter.italic(
                    text_descr)

        if deprecated_descr:
            formatted_details['descr'] += ' ' + self.formatter.italic(
                deprecated_descr)

        prop_type = html.escape(formatted_details['prop_type'], False)
        if has_enum:
            prop_type += '<br>(enum)'
        if formatted_details['prop_units']:
            prop_type += '<br>(' + formatted_details['prop_units'] + ')'

        if in_array:
            prop_type = 'array (' + prop_type + ')'

        if collapse_array:
            item_list = formatted_details['item_list']
            if len(item_list):
                if isinstance(item_list, list):
                    item_list = ', '.join([html.escape(x) for x in item_list])
                prop_type += '<br>(' + item_list + ')'

        prop_access = ''
        if not formatted_details['prop_is_object']:
            if formatted_details['read_only']:
                prop_access = '<nobr>read-only</nobr>'
            else:
                prop_access = '<nobr>read-write</nobr>'

        if formatted_details['prop_required_on_create']:
            prop_access += ' <nobr>required on create</nobr>'
        elif formatted_details['prop_required'] or formatted_details.get(
                'required_parameter'):
            prop_access += ' <nobr>required</nobr>'

        if formatted_details['nullable']:
            prop_access += ' (null)'

        # If profile reqs are present, massage them:
        profile_access = self.format_base_profile_access(formatted_details)

        descr = formatted_details['descr']
        if formatted_details['profile_purpose']:
            descr += '<br>' + self.formatter.bold(
                "Profile Purpose: " + formatted_details['profile_purpose'])

        # Conditional Requirements
        cond_req = formatted_details['profile_conditional_req']
        if cond_req:
            anchor = schema_ref + '|conditional_reqs|' + prop_name
            cond_req_text = 'See <a href="#' + anchor + '"> Conditional Requirements</a>, below, for more information.'
            descr += ' ' + self.formatter.nobr(
                self.formatter.italic(cond_req_text))
            profile_access += "<br>" + self.formatter.nobr(
                self.formatter.italic('Conditional Requirements'))

        if not profile_access:
            profile_access = '&nbsp;' * 10

        # Comparison
        if formatted_details['profile_values']:
            comparison_descr = (
                'Must be ' + formatted_details['profile_comparison'] + ' (' +
                ', '.join('"' + x + '"'
                          for x in formatted_details['profile_values']) + ')')
            profile_access += '<br>' + self.formatter.italic(comparison_descr)

        row = []
        row.append(indentation_string + name_and_version)
        if self.config.get('profile_mode'):
            row.append(profile_access)
        row.append(prop_type)
        if not self.config.get('profile_mode'):
            row.append(prop_access)
        row.append(descr)

        formatted.append(self.formatter.make_row(row))

        if len(formatted_details['object_description']) > 0:
            formatted_object = formatted_details['object_description']
            # Add a closing } to the last row of this object.
            formatted_object = self._add_closing_brace(formatted_object,
                                                       indentation_string, '}')
            formatted.append(formatted_object)

        if not collapse_array and len(
                formatted_details['item_description']) > 0:
            formatted_array = formatted_details['item_description']
            # Add closing }] or ] to the last row of this array:
            if formatted_details['array_of_objects']:
                formatted_array = self._add_closing_brace(
                    formatted_array, indentation_string, '} ]')
            else:
                formatted_array = self._add_closing_brace(
                    formatted_array, indentation_string, ']')
            formatted.append(formatted_array)

        return ({
            'row':
            '\n'.join(formatted),
            'details':
            formatted_details['prop_details'],
            'action_details':
            formatted_details.get('action_details'),
            'profile_conditional_details':
            formatted_details.get('profile_conditional_details')
        })
Example #3
0
    def format_property_details(self,
                                prop_name,
                                prop_type,
                                prop_description,
                                enum,
                                enum_details,
                                supplemental_details,
                                meta,
                                anchor=None,
                                profile=None):
        """Generate a formatted table of enum information for inclusion in Property Details."""

        contents = []
        contents.append(
            self.formatter.head_four(
                html.escape(prop_name, False) + ':', self.level, anchor))

        parent_version = meta.get('version')
        enum_meta = meta.get('enum', {})

        # Are we in profile mode? If so, consult the profile passed in for this property.
        # For Action Parameters, look for ParameterValues/RecommendedValues; for
        # Property enums, look for MinSupportValues/RecommendedValues.
        profile_mode = self.config.get('profile_mode')
        if profile_mode:
            if profile is None:
                profile = {}
            profile_values = profile.get('Values', [])
            profile_min_support_values = profile.get('MinSupportValues', [])
            profile_parameter_values = profile.get('ParameterValues', [])
            profile_recommended_values = profile.get('RecommendedValues', [])

            profile_all_values = (profile_values + profile_min_support_values +
                                  profile_parameter_values +
                                  profile_recommended_values)

        if prop_description:
            contents.append(self.formatter.para(prop_description))

        if isinstance(prop_type, list):
            prop_type = ', '.join([html.escape(x, False) for x in prop_type])
        else:
            prop_type = html.escape(prop_type, False)

        if supplemental_details:
            contents.append(
                self.formatter.markdown_to_html(supplemental_details))

        if enum_details:
            headings = [prop_type, 'Description']
            if profile_mode:
                headings.append('Profile Specifies')
            header_row = self.formatter.make_header_row(headings)
            table_rows = []
            enum.sort(key=str.lower)

            for enum_item in enum:
                enum_name = html.escape(enum_item, False)
                enum_item_meta = enum_meta.get(enum_item, {})
                version_display = None
                deprecated_descr = None

                if 'version' in enum_item_meta:
                    version = enum_item_meta['version']
                    if not parent_version or DocGenUtilities.compare_versions(
                            version, parent_version) > 0:
                        version_text = html.escape(version, False)
                        version_display = self.truncate_version(
                            version_text, 2) + '+'

                if version_display:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = html.escape(
                            enum_item_meta['version_deprecated'], False)
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ', deprecated v' +
                            deprecated_display + ')')
                        if enum_item_meta.get(
                                'version_deprecated_explanation'):
                            deprecated_descr = html.escape(
                                'Deprecated v' + deprecated_display + '+. ' +
                                enum_item_meta[
                                    'version_deprecated_explanation'], False)
                    else:
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ')')
                elif 'version_deprecated' in enum_item_meta:
                    version_depr = html.escape(
                        enum_item_meta['version_deprecated'], False)
                    deprecated_display = self.truncate_version(version_depr, 2)
                    enum_name += ' ' + self.formatter.italic(
                        '(deprecated v' + deprecated_display + ')')
                    if enum_item_meta.get('version_deprecated_explanation'):
                        deprecated_descr = html.escape(
                            'Deprecated v' + deprecated_display + '+. ' +
                            enum_item_meta['version_deprecated_explanation'],
                            False)

                descr = html.escape(enum_details.get(enum_item, ''), False)
                if deprecated_descr:
                    if descr:
                        descr += ' ' + self.formatter.italic(deprecated_descr)
                    else:
                        descr = self.formatter.italic(deprecated_descr)
                cells = [enum_name, descr]

                if profile_mode:
                    if enum_name in profile_values:
                        cells.append('Required')
                    elif enum_name in profile_min_support_values:
                        cells.append('Required')
                    elif enum_name in profile_parameter_values:
                        cells.append('Required')
                    elif enum_name in profile_recommended_values:
                        cells.append('Recommended')
                    else:
                        cells.append('')

                table_rows.append(self.formatter.make_row(cells))
            contents.append(
                self.formatter.make_table(table_rows, [header_row],
                                          'enum enum-details'))

        elif enum:
            headings = [prop_type]
            if profile_mode:
                headings.append('Profile Specifies')
            header_row = self.formatter.make_header_row(headings)
            table_rows = []
            enum.sort(key=str.lower)
            for enum_item in enum:
                enum_name = html.escape(enum_item, False)
                enum_item_meta = enum_meta.get(enum_item, {})
                version_display = None

                if 'version' in enum_item_meta:
                    version = enum_item_meta['version']
                    if not parent_version or DocGenUtilities.compare_versions(
                            version, parent_version) > 0:
                        version_text = html.escape(version, False)
                        version_display = self.truncate_version(
                            version_text, 2) + '+'

                if version_display:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = html.escape(
                            enum_item_meta['version_deprecated'], False)
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ', deprecated v' +
                            deprecated_display + ')')
                        if enum_item_meta.get(
                                'version_deprecated_explanation'):
                            enum_name += '<br>' + self.formatter.italic(
                                html.escape(
                                    'Deprecated v' + deprecated_display +
                                    '+. ' + enum_item_meta[
                                        'version_deprecated_explanation'],
                                    False))
                    else:
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ')')

                elif 'version_deprecated' in enum_item_meta:
                    version_depr = html.escape(
                        enum_item_meta['version_deprecated'], False)
                    deprecated_display = self.truncate_version(version_depr, 2)
                    enum_name += ' ' + self.formatter.italic(
                        '(deprecated v' + deprecated_display + ')')
                    if enum_item_meta.get('version_deprecated_explanation'):
                        enum_name += '<br>' + self.formatter.italic(
                            html.escape(
                                'Deprecated v' + deprecated_display + '+. ' +
                                enum_item_meta[
                                    'version_deprecated_explanation'], False))

                cells = [enum_name]
                if profile_mode:
                    if enum_name in profile_values:
                        cells.append('Required')
                    elif enum_name in profile_min_support_values:
                        cells.append('Required')
                    elif enum_name in profile_parameter_values:
                        cells.append('Required')
                    elif enum_name in profile_recommended_values:
                        cells.append('Recommended')
                    else:
                        cells.append('')

                table_rows.append(self.formatter.make_row(cells))
            contents.append(
                self.formatter.make_table(table_rows, [header_row], 'enum'))

        return '\n'.join(contents) + '\n'
Example #4
0
    def format_property_row(self, schema_ref, prop_name, prop_info, prop_path=[], in_array=False):
        """Format information for a single property.

        Returns an object with 'row', 'details', 'action_details', and 'profile_conditional_details':

        'row': content for the main table being generated.
        'details': content for the Property Details section.
        'action_details': content for the Actions section.
        'profile_conditional_details': populated only in profile_mode, formatted conditional details

        This may include embedded objects with their own properties.
        """

        traverser = self.traverser
        formatted = []     # The row itself

        current_depth = len(prop_path)

        if in_array:
            current_depth = current_depth -1

        # strip_top_object is used for fragments, to allow output of just the properties
        # without the enclosing object:
        if self.config.get('strip_top_object') and current_depth > 0:
            indentation_string = '&nbsp;' * 6 * (current_depth -1)
        else:
            indentation_string = '&nbsp;' * 6 * current_depth

        # If prop_path starts with Actions and is more than 1 deep, we are outputting for an Actions
        # section and should dial back the indentation by one level.
        if len(prop_path) > 1 and prop_path[0] == 'Actions':
            indentation_string = '&nbsp;' * 6 * (current_depth -1)

        collapse_array = False # Should we collapse a list description into one row? For lists of simple types
        has_enum = False

        if current_depth < self.current_depth:
            for i in range(current_depth, self.current_depth):
                if i in self.current_version:
                    del self.current_version[i]
        self.current_depth = current_depth
        parent_depth = current_depth - 1

        if isinstance(prop_info, list):
            meta = prop_info[0].get('_doc_generator_meta')
            has_enum = 'enum' in prop_info[0]
            is_excerpt = prop_info[0].get('_is_excerpt') or prop_info[0].get('excerptCopy')
        elif isinstance(prop_info, dict):
            meta = prop_info.get('_doc_generator_meta')
            has_enum = 'enum' in prop_info
            is_excerpt = prop_info.get('_is_excerpt')

        if not meta:
            meta = {}

        # We want to modify a local copy of meta, deleting redundant version info
        meta = copy.deepcopy(meta)

        name_and_version = self.formatter.bold(html.escape(prop_name, False))
        deprecated_descr = None

        version = meta.get('version')
        self.current_version[current_depth] = version

        # Don't display version if there is a parent version and this is not newer:
        if self.current_version.get(parent_depth) and version:
            if DocGenUtilities.compare_versions(version, self.current_version.get(parent_depth)) <= 0:
                del meta['version']

        if meta.get('version', '1.0.0') != '1.0.0':
            version_text = html.escape(meta['version'], False)
            version_display = self.truncate_version(version_text, 2) + '+'
            if 'version_deprecated' in meta:
                version_depr = html.escape(meta['version_deprecated'], False)
                deprecated_display = self.truncate_version(version_depr, 2)
                name_and_version += ' ' + self.formatter.italic('(v' + version_display +
                                                      ', deprecated v' + deprecated_display +  ')')
                deprecated_descr = html.escape("Deprecated v" + deprecated_display + '+. ' +
                                               meta['version_deprecated_explanation'], False)
            else:
                name_and_version += ' ' + self.formatter.italic('(v' + version_display + ')')
        elif 'version_deprecated' in meta:
            version_depr = html.escape(meta['version_deprecated'], False)
            deprecated_display = self.truncate_version(version_depr, 2)
            name_and_version += ' ' + self.formatter.italic('(deprecated v' + deprecated_display +  ')')
            deprecated_descr = html.escape( "Deprecated v" + deprecated_display + '+. ' +
                                            meta['version_deprecated_explanation'], False)

        formatted_details = self.parse_property_info(schema_ref, prop_name, prop_info, prop_path,
                                                     meta.get('within_action'))

        if formatted_details.get('promote_me'):
            return({'row': '\n'.join(formatted_details['item_description']), 'details':formatted_details['prop_details'],
                    'action_details':formatted_details.get('action_details')})


        if self.config.get('strip_top_object') and current_depth == 0:
            # In this case, we're done for this bit of documentation, and we just want the properties of this object.
            formatted.append('\n'.join(formatted_details['object_description']))
            return({'row': '\n'.join(formatted), 'details':formatted_details['prop_details'],
                    'action_details':formatted_details.get('action_details'),
                    'profile_conditional_details':formatted_details.get('profile_conditional_details')})

        # Eliminate dups in these these properties and join with a delimiter:
        props = {
            'prop_type': self.separators['inline'],
            'descr': self.separators['linebreak'],
            'object_description': '\n',
            'item_description': '\n'
            }

        for property_name, delim in props.items():
            if isinstance(formatted_details[property_name], list):
                property_values = []
                self.append_unique_values(formatted_details[property_name], property_values)
                formatted_details[property_name] = delim.join(property_values)

        if formatted_details['prop_is_object'] and not in_array:
            if formatted_details['object_description'] == '':
                name_and_version += ' { }'
            else:
                name_and_version += ' {'

        if formatted_details['prop_is_array']:
            if formatted_details['item_description'] == '':
                if formatted_details['array_of_objects']:
                    name_and_version += ' [ { } ]'
                else:
                    name_and_version += ' [ ] '
            else:
                if formatted_details['array_of_objects']:
                    name_and_version += ' [ {'
                else:
                    collapse_array = True
                    name_and_version += ' [ ] '
        elif in_array:
            if formatted_details['prop_is_object']:
                name_and_version += ' [ { } ]'
            else:
                name_and_version += ' [ ] '

        name_and_version = '<nobr>' + name_and_version  + '</nobr>'

        if formatted_details['descr'] is None:
            formatted_details['descr'] = ''

        if not formatted_details.get('verbatim_description', False):
            formatted_details['descr'] = self.formatter.markdown_to_html(html.escape(formatted_details['descr'], False), no_para=True)

        if formatted_details['add_link_text']:
            if formatted_details['descr']:
                formatted_details['descr'] += self.formatter.br()
            formatted_details['descr'] += self.formatter.italic(formatted_details['add_link_text'])

        # Append reference info to descriptions, if appropriate:
        if not formatted_details.get('fulldescription_override'):
            # If there are prop_details (enum details), add a note to the description:
            if formatted_details['has_direct_prop_details'] and not formatted_details['has_action_details']:
                if has_enum:
                    anchor = schema_ref + '|details|' + prop_name
                    text_descr = 'See <a href="#' + anchor + '">' + prop_name + '</a> in Property Details, below, for the possible values of this property.'
                else:
                    text_descr = 'See Property Details, below, for more information about this property.'


                if formatted_details['descr']:
                    formatted_details['descr'] += '<br>' + self.formatter.italic(text_descr)
                else:
                    formatted_details['descr'] = self.formatter.italic(text_descr)

            # If this is an Action with details, add a note to the description:
            if formatted_details['has_action_details']:
                anchor = schema_ref + '|action_details|' + prop_name
                text_descr = 'For more information, see the <a href="#' + anchor + '">Actions</a> section below.'
                formatted_details['descr'] += '<br>' + self.formatter.italic(text_descr)

        if deprecated_descr:
            formatted_details['descr'] += ' ' + self.formatter.italic(deprecated_descr)

        prop_type = html.escape(formatted_details['prop_type'], False)
        if has_enum:
            prop_type += '<br>(enum)'
        if formatted_details['prop_units']:
            prop_type += '<br>(' + formatted_details['prop_units'] + ')'
        if is_excerpt:
            prop_type += '<br>(excerpt)'

        if in_array:
            prop_type = 'array (' + prop_type + ')'

        if collapse_array:
            item_list = formatted_details['item_list']
            if len(item_list):
                if isinstance(item_list, list):
                    item_list = ', '.join([html.escape(x) for x in item_list])
                prop_type += '<br>(' + item_list + ')'

        prop_access = ''
        if not meta.get('is_pattern') and not formatted_details['prop_is_object']:
            if formatted_details['read_only']:
                prop_access = '<nobr>read-only</nobr>'
            else:
                prop_access = '<nobr>read-write</nobr>'

        if formatted_details['prop_required'] or formatted_details.get('required_parameter'):
            prop_access += ' <nobr>required</nobr>'
        elif formatted_details['prop_required_on_create']:
            prop_access += ' <nobr>required on create</nobr>'

        if formatted_details['nullable']:
            prop_access += ' (null)'

        # If profile reqs are present, massage them:
        profile_access = self.format_base_profile_access(formatted_details)

        descr = formatted_details['descr']
        if formatted_details['profile_purpose']:
            descr += '<br>' + self.formatter.bold("Profile Purpose: " + formatted_details['profile_purpose'])

        # Conditional Requirements
        cond_req = formatted_details['profile_conditional_req']
        if cond_req:
            anchor = schema_ref + '|conditional_reqs|' + prop_name
            cond_req_text = 'See <a href="#' + anchor + '"> Conditional Requirements</a>, below, for more information.'
            descr += ' ' + self.formatter.nobr(self.formatter.italic(cond_req_text))
            profile_access += "<br>" + self.formatter.nobr(self.formatter.italic('Conditional Requirements'))

        if not profile_access:
            profile_access = '&nbsp;' * 10

        # Comparison
        if formatted_details['profile_values']:
            comparison_descr = ('Must be ' + formatted_details['profile_comparison'] + ' ('
                                + ', '.join('"' + x + '"' for x in formatted_details['profile_values'])
                                + ')')
            profile_access += '<br>' + self.formatter.italic(comparison_descr)

        row = []
        row.append(indentation_string + name_and_version)
        if self.config.get('profile_mode'):
            row.append(profile_access)
        row.append(prop_type)
        if not self.config.get('profile_mode'):
            row.append(prop_access)
        row.append(descr)

        formatted.append(self.formatter.make_row(row))

        if len(formatted_details['object_description']) > 0:
            formatted_object = formatted_details['object_description']
            # Add a closing } to the last row of this object.
            formatted_object = self._add_closing_brace(formatted_object, indentation_string, '}')
            formatted.append(formatted_object)

        if not collapse_array and len(formatted_details['item_description']) > 0:
            formatted_array = formatted_details['item_description']
            # Add closing }] or ] to the last row of this array:
            if formatted_details['array_of_objects']:
                formatted_array = self._add_closing_brace(formatted_array, indentation_string, '} ]')
            else:
                formatted_array = self._add_closing_brace(formatted_array, indentation_string, ']')
            formatted.append(formatted_array)

        return({'row': '\n'.join(formatted), 'details':formatted_details['prop_details'],
                'action_details':formatted_details.get('action_details'),
                'profile_conditional_details':formatted_details.get('profile_conditional_details')})
Example #5
0
    def format_property_details(self, prop_name, prop_type, prop_description, enum, enum_details,
                                supplemental_details, meta, anchor=None, profile=None):
        """Generate a formatted table of enum information for inclusion in Property Details."""

        contents = []
        contents.append(self.formatter.head_four(html.escape(prop_name, False) + ':', self.level, anchor))

        parent_version = meta.get('version')
        enum_meta = meta.get('enum', {})

        # Are we in profile mode? If so, consult the profile passed in for this property.
        # For Action Parameters, look for ParameterValues/RecommendedValues; for
        # Property enums, look for MinSupportValues/RecommendedValues.
        profile_mode = self.config.get('profile_mode')
        if profile_mode:
            if profile is None:
                profile = {}
            profile_values = profile.get('Values', [])
            profile_min_support_values = profile.get('MinSupportValues', [])
            profile_parameter_values = profile.get('ParameterValues', [])
            profile_recommended_values = profile.get('RecommendedValues', [])

            profile_all_values = (profile_values + profile_min_support_values + profile_parameter_values
                                  + profile_recommended_values)

        if prop_description:
            contents.append(self.formatter.para(prop_description))

        if isinstance(prop_type, list):
            prop_type = ', '.join([html.escape(x, False) for x in prop_type])
        else:
            prop_type = html.escape(prop_type, False)

        if supplemental_details:
            contents.append(self.formatter.markdown_to_html(supplemental_details))

        if enum_details:
            headings = [prop_type, 'Description']
            if profile_mode:
                headings.append('Profile Specifies')
            header_row = self.formatter.make_header_row(headings)
            table_rows = []
            enum.sort(key=str.lower)

            for enum_item in enum:
                enum_name = html.escape(enum_item, False)
                enum_item_meta = enum_meta.get(enum_item, {})
                version_display = None
                deprecated_descr = None

                if 'version' in enum_item_meta:
                    version = enum_item_meta['version']
                    if not parent_version or DocGenUtilities.compare_versions(version, parent_version) > 0:
                        version_text = html.escape(version, False)
                        version_display = self.truncate_version(version_text, 2) + '+'

                if version_display:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = html.escape(enum_item_meta['version_deprecated'], False)
                        deprecated_display = self.truncate_version(version_depr, 2)
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ', deprecated v' + deprecated_display + ')')
                        if enum_item_meta.get('version_deprecated_explanation'):
                            deprecated_descr = html.escape('Deprecated v' + deprecated_display + '+. ' +
                                                           enum_item_meta['version_deprecated_explanation'], False)
                    else:
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ')')
                elif 'version_deprecated' in enum_item_meta:
                    version_depr = html.escape(enum_item_meta['version_deprecated'], False)
                    deprecated_display = self.truncate_version(version_depr, 2)
                    enum_name += ' ' + self.formatter.italic('(deprecated v' + deprecated_display + ')')
                    if enum_item_meta.get('version_deprecated_explanation'):
                        deprecated_descr = html.escape('Deprecated v' + deprecated_display + '+. ' +
                                                       enum_item_meta['version_deprecated_explanation'], False)

                descr = html.escape(enum_details.get(enum_item, ''), False)
                if deprecated_descr:
                    if descr:
                        descr += ' ' + self.formatter.italic(deprecated_descr)
                    else:
                        descr = self.formatter.italic(deprecated_descr)
                cells = [enum_name, descr]

                if profile_mode:
                    if enum_name in profile_values:
                        cells.append('Required')
                    elif enum_name in profile_min_support_values:
                        cells.append('Required')
                    elif enum_name in profile_parameter_values:
                        cells.append('Required')
                    elif enum_name in profile_recommended_values:
                        cells.append('Recommended')
                    else:
                        cells.append('')

                table_rows.append(self.formatter.make_row(cells))
            contents.append(self.formatter.make_table(table_rows, [header_row], 'enum enum-details'))

        elif enum:
            headings = [prop_type]
            if profile_mode:
                headings.append('Profile Specifies')
            header_row = self.formatter.make_header_row(headings)
            table_rows = []
            enum.sort(key=str.lower)
            for enum_item in enum:
                enum_name = html.escape(enum_item, False)
                enum_item_meta = enum_meta.get(enum_item, {})
                version_display = None

                if 'version' in enum_item_meta:
                    version = enum_item_meta['version']
                    if not parent_version or DocGenUtilities.compare_versions(version, parent_version) > 0:
                        version_text = html.escape(version, False)
                        version_display = self.truncate_version(version_text, 2) + '+'

                if version_display:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = html.escape(enum_item_meta['version_deprecated'], False)
                        deprecated_display = self.truncate_version(version_depr, 2)
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ', deprecated v' + deprecated_display + ')')
                        if enum_item_meta.get('version_deprecated_explanation'):
                            enum_name += '<br>' + self.formatter.italic(html.escape('Deprecated v' + deprecated_display + '+. ' +
                                                                          enum_item_meta['version_deprecated_explanation'], False))
                    else:
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ')')

                elif 'version_deprecated' in enum_item_meta:
                    version_depr = html.escape(enum_item_meta['version_deprecated'], False)
                    deprecated_display = self.truncate_version(version_depr, 2)
                    enum_name += ' ' + self.formatter.italic('(deprecated v' + deprecated_display + ')')
                    if enum_item_meta.get('version_deprecated_explanation'):
                        enum_name += '<br>' + self.formatter.italic(html.escape('Deprecated v' + deprecated_display + '+. ' +
                                                                      enum_item_meta['version_deprecated_explanation'], False))

                cells = [enum_name]
                if profile_mode:
                    if enum_name in profile_values:
                        cells.append('Required')
                    elif enum_name in profile_min_support_values:
                        cells.append('Required')
                    elif enum_name in profile_parameter_values:
                        cells.append('Required')
                    elif enum_name in profile_recommended_values:
                        cells.append('Recommended')
                    else:
                        cells.append('')

                table_rows.append(self.formatter.make_row(cells))
            contents.append(self.formatter.make_table(table_rows, [header_row], 'enum'))

        return '\n'.join(contents) + '\n'
    def format_property_row(self,
                            schema_ref,
                            prop_name,
                            prop_info,
                            prop_path=[],
                            in_array=False,
                            as_action_parameters=False):
        """Format information for a single property.

        Returns an object with 'row', 'details', 'action_details', and 'profile_conditional_details':

        'row': content for the main table being generated.
        'details': content for the Property details section.
        'action_details': content for the Actions section.
        'profile_conditional_details': populated only in profile_mode, formatted conditional details

        This may include embedded objects with their own properties.
        """

        traverser = self.traverser
        formatted = []  # The row itself

        within_action = prop_path == ['Actions']
        current_depth = len(prop_path)
        if in_array:
            current_depth = current_depth - 1

        # strip_top_object is used for fragments, to allow output of just the properties
        # without the enclosing object:
        if self.config.get('strip_top_object') and current_depth > 0:
            indentation_string = '&nbsp;' * 6 * (current_depth - 1)
        else:
            indentation_string = '&nbsp;' * 6 * current_depth

        # If prop_path starts with Actions and is more than 1 deep, we are outputting for an Actions
        # section and should dial back the indentation by one level.
        if len(prop_path) > 1 and prop_path[0] == 'Actions':
            indentation_string = '&nbsp;' * 6 * (current_depth - 1)

        collapse_array = False  # Should we collapse a list description into one row? For lists of simple types
        has_enum = False

        if current_depth < self.current_depth:
            for i in range(current_depth, self.current_depth):
                if i in self.current_version:
                    del self.current_version[i]
        self.current_depth = current_depth
        parent_depth = current_depth - 1

        version_added = None
        version_deprecated = None
        version_deprecated_explanation = ''
        if isinstance(prop_info, list):
            version_added = prop_info[0].get('versionAdded')
            version_deprecated = prop_info[0].get('versionDeprecated')
            version_deprecated_explanation = prop_info[0].get('deprecated')
            has_enum = 'enum' in prop_info[0]
            is_excerpt = prop_info[0].get('_is_excerpt') or prop_info[0].get(
                'excerptCopy')
        elif isinstance(prop_info, dict):
            version_added = prop_info.get('versionAdded')
            version_deprecated = prop_info.get('versionDeprecated')
            version_deprecated_explanation = prop_info.get('deprecated')
            has_enum = 'enum' in prop_info
            is_excerpt = prop_info[0].get('_is_excerpt')

        if prop_name:
            name_and_version = self.formatter.bold(
                self.escape_for_markdown(prop_name,
                                         self.config.get('escape_chars', [])))
        else:
            name_and_version = ''

        deprecated_descr = None

        version = None
        if version_added:
            version = self.format_version(version_added)
        if version_deprecated:
            version_depr = self.format_version(version_deprecated)
        self.current_version[current_depth] = version

        # Don't display version if there is a parent version and this is not newer:
        if version and self.current_version.get(parent_depth):
            if DocGenUtilities.compare_versions(
                    version, self.current_version.get(parent_depth)) <= 0:
                version = None

        if version and version != '1.0.0':
            version_display = self.truncate_version(version, 2) + '+'
            if version_deprecated:
                deprecated_display = self.truncate_version(version_depr, 2)
                name_and_version += ' ' + self.formatter.italic(
                    '(v' + version_display + ', deprecated v' +
                    deprecated_display + ')')
                deprecated_descr = ("Deprecated in v" + deprecated_display +
                                    ' and later. ' + self.escape_for_markdown(
                                        version_deprecated_explanation,
                                        self.config.get('escape_chars', [])))
            else:
                name_and_version += ' ' + self.formatter.italic(
                    '(v' + version_display + ')')
        elif version_deprecated:
            deprecated_display = self.truncate_version(version_depr, 2)
            name_and_version += ' ' + self.formatter.italic(
                '(deprecated v' + deprecated_display + ')')
            deprecated_descr = (
                "Deprecated in v" + deprecated_display + ' and later. ' +
                self.escape_for_markdown(version_deprecated_explanation,
                                         self.config.get('escape_chars', [])))

        formatted_details = self.parse_property_info(schema_ref, prop_name,
                                                     prop_info, prop_path)

        if formatted_details.get('promote_me'):
            return ({
                'row': '\n'.join(formatted_details['item_description']),
                'details': formatted_details['prop_details'],
                'action_details': formatted_details.get('action_details')
            })

        if self.config.get('strip_top_object') and current_depth == 0:
            # In this case, we're done for this bit of documentation, and we just want the properties of this object.
            formatted.append('\n'.join(
                formatted_details['object_description']))
            return ({
                'row':
                '\n'.join(formatted),
                'details':
                formatted_details['prop_details'],
                'action_details':
                formatted_details.get('action_details'),
                'profile_conditional_details':
                formatted_details.get('profile_conditional_details')
            })

        # Eliminate dups in these these properties and join with a delimiter:
        props = {
            'prop_type': self.separators['inline'],
            'descr': self.separators['linebreak'],
            'object_description': self.separators['linebreak'],
            'item_description': self.separators['linebreak']
        }

        for property_name, delim in props.items():
            if isinstance(formatted_details[property_name], list):
                property_values = []
                self.append_unique_values(formatted_details[property_name],
                                          property_values)
                formatted_details[property_name] = delim.join(property_values)

        if formatted_details['prop_is_object'] and not in_array:
            if formatted_details['object_description'] == '':
                name_and_version += ' {}'
            else:
                name_and_version += ' {'

        if formatted_details['prop_is_array']:
            if formatted_details['item_description'] == '':
                if formatted_details['array_of_objects']:
                    name_and_version += ' [ {} ]'
                else:
                    name_and_version += ' [ ]'
            else:
                if formatted_details['array_of_objects']:
                    name_and_version += ' [ {'
                else:
                    collapse_array = True
                    name_and_version += ' [ ]'
        elif in_array:
            if formatted_details['prop_is_object']:
                name_and_version += ' [ { } ]'
            else:
                name_and_version += ' [ ]'

        if formatted_details['descr'] is None:
            formatted_details['descr'] = ''

        if formatted_details['profile_purpose'] and (
                self.config.get('profile_mode') != 'subset'):
            if formatted_details['descr']:
                formatted_details['descr'] += ' '
            formatted_details['descr'] += self.formatter.bold(
                formatted_details['profile_purpose'])

        if formatted_details['add_link_text']:
            if formatted_details['descr']:
                formatted_details['descr'] += ' '
            formatted_details['descr'] += formatted_details['add_link_text']

        # Append reference info to descriptions, if appropriate:
        if not formatted_details.get('fulldescription_override'):
            if formatted_details[
                    'has_direct_prop_details'] and not formatted_details[
                        'has_action_details']:
                # If there are prop_details (enum details), add a note to the description:
                if has_enum:
                    text_descr = 'For the possible property values, see ' + prop_name + ' in Property details.'
                else:
                    text_descr = 'For more information about this property, see Property details.'
                formatted_details['descr'] += ' ' + self.formatter.italic(
                    text_descr)

            if formatted_details['has_action_details']:
                text_descr = 'For more information, see the Actions section below.'
                formatted_details['descr'] += ' ' + self.formatter.italic(
                    text_descr)

        if deprecated_descr:
            formatted_details['descr'] += ' ' + self.formatter.italic(
                deprecated_descr)

        prop_type = formatted_details['prop_type']
        if has_enum:
            prop_type += '<br>(enum)'

        if formatted_details['prop_units']:
            prop_type += '<br>(' + formatted_details['prop_units'] + ')'

        if is_excerpt:
            prop_type += '<br>(excerpt)'

        if in_array:
            prop_type = 'array (' + prop_type + ')'

        if collapse_array:
            item_list = formatted_details['item_list']
            if len(item_list):
                if isinstance(item_list, list):
                    item_list = ', '.join(item_list)
                prop_type += ' (' + item_list + ')'

        prop_access = ''
        if (not formatted_details['prop_is_object']
                and not formatted_details.get('array_of_objects')
                and not as_action_parameters):
            if formatted_details['read_only']:
                prop_access = 'read-only'
            else:
                # Special case for subset mode; if profile indicates WriteRequirement === None (present and None),
                # emit read-only.
                if ((self.config.get('profile_mode') == 'subset')
                        and formatted_details.get('profile_write_req') and
                    (formatted_details['profile_write_req'] == 'None')):
                    prop_access = 'read-only'
                else:
                    prop_access = 'read-write'

        # Action parameters don't have read/write properties, but they can be required/optional.
        if as_action_parameters:
            if formatted_details['prop_required'] or formatted_details[
                    'required_parameter']:
                prop_access = 'required'
            else:
                prop_access = 'optional'
        else:
            if formatted_details['prop_required'] or formatted_details[
                    'required_parameter']:
                prop_access += ' required'
            elif formatted_details['prop_required_on_create']:
                prop_access += ' required on create'

        if formatted_details['nullable']:
            prop_access += '<br>(null)'

        # If profile reqs are present, massage them:
        profile_access = self.format_base_profile_access(formatted_details)

        if self.config.get('profile_mode'
                           ) and self.config.get('profile_mode') != 'subset':
            if profile_access:
                prop_type += '<br><br>' + self.formatter.italic(profile_access)
        elif prop_access:
            prop_type += '<br><br>' + self.formatter.italic(prop_access)

        row = []
        row.append(indentation_string + name_and_version)
        row.append(prop_type)
        row.append(formatted_details['descr'])

        formatted.append('| ' + ' | '.join(row) + ' |')

        if len(formatted_details['object_description']) > 0:
            formatted.append(formatted_details['object_description'])
            formatted.append('| ' + indentation_string + '} |   |   |')

        if not collapse_array and len(
                formatted_details['item_description']) > 0:
            formatted.append(formatted_details['item_description'])
            if formatted_details['array_of_objects']:
                formatted.append('| ' + indentation_string + '} ] |   |   |')
            else:
                formatted.append('| ' + indentation_string + '] |   |   |')

        return ({
            'row':
            '\n'.join(formatted),
            'details':
            formatted_details['prop_details'],
            'action_details':
            formatted_details.get('action_details'),
            'profile_conditional_details':
            formatted_details.get('profile_conditional_details')
        })
    def format_property_details(self,
                                prop_name,
                                prop_type,
                                prop_description,
                                enum,
                                enum_details,
                                supplemental_details,
                                parent_prop_info,
                                anchor=None,
                                profile=None):
        """Generate a formatted table of enum information for inclusion in Property details."""

        contents = []
        contents.append(self.formatter.head_three(prop_name + ':', self.level))

        parent_version = parent_prop_info.get('versionAdded')
        if parent_version:
            parent_version = self.format_version(parent_version)

        # Are we in profile mode? If so, consult the profile passed in for this property.
        # For Action Parameters, look for ParameterValues/RecommendedValues; for
        # Property enums, look for MinSupportValues/RecommendedValues.
        profile_mode = self.config.get('profile_mode')
        if profile_mode:
            if profile is None:
                profile = {}

            profile_values = profile.get('Values', [])
            profile_min_support_values = profile.get(
                'MinSupportValues', [])  # No longer a valid name?
            profile_parameter_values = profile.get('ParameterValues', [])
            profile_recommended_values = profile.get('RecommendedValues', [])

            # profile_all_values is not used. What were we going for here?
            profile_all_values = (profile_values + profile_min_support_values +
                                  profile_parameter_values +
                                  profile_recommended_values)

            # In subset mode, an action parameter with no Values (property) or ParameterValues (Action)
            # means all values are supported.
            # Otherwise, Values/ParameterValues specifies the set that should be listed.
            if profile_mode == 'subset':
                if len(profile_values):
                    enum = [x for x in enum if x in profile_values]
                elif len(profile_parameter_values):
                    enum = [x for x in enum if x in profile_parameter_values]

        if prop_description:
            contents.append(
                self.formatter.para(
                    self.escape_for_markdown(
                        prop_description, self.config.get('escape_chars',
                                                          []))))

        if isinstance(prop_type, list):
            prop_type = ', '.join(prop_type)

        if supplemental_details:
            contents.append('\n' + supplemental_details + '\n')

        if enum_details:
            if profile_mode and profile_mode != 'subset':
                contents.append('| ' + prop_type +
                                ' | Description | Profile Specifies |')
                contents.append('| --- | --- | --- |')
            else:
                contents.append('| ' + prop_type + ' | Description |')
                contents.append('| --- | --- |')
            enum.sort(key=str.lower)
            for enum_item in enum:
                enum_name = enum_item
                version = version_depr = deprecated_descr = None
                version_display = None
                if parent_prop_info.get('enumVersionAdded'):
                    version_added = parent_prop_info.get(
                        'enumVersionAdded').get(enum_name)
                    if version_added:
                        version = self.format_version(version_added)
                if parent_prop_info.get('enumVersionDeprecated'):
                    version_deprecated = parent_prop_info.get(
                        'enumVersionDeprecated').get(enum_name)
                    if version_deprecated:
                        version_depr = self.format_version(version_deprecated)
                if parent_prop_info.get('enumDeprecated'):
                    deprecated_descr = parent_prop_info.get(
                        'enumDeprecated').get(enum_name)

                if version:
                    if not parent_version or DocGenUtilities.compare_versions(
                            version, parent_version) > 0:
                        version_display = self.truncate_version(version,
                                                                2) + '+'

                if version_display:
                    if version_depr:
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ', deprecated v' +
                            deprecated_display + ')')
                        if deprecated_descr:
                            deprecated_descr = 'Deprecated in v' + deprecated_display + ' and later. ' + deprecated_descr
                    else:
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ')')
                elif version_depr:
                    deprecated_display = self.truncate_version(version_depr, 2)
                    enum_name += ' ' + self.formatter.italic(
                        '(deprecated v' + deprecated_display + ')')
                    if deprecated_descr:
                        deprecated_descr = 'Deprecated in v' + deprecated_display + ' and later. ' + deprecated_descr

                descr = enum_details.get(enum_item, '')
                if deprecated_descr:
                    if descr:
                        descr += ' ' + self.formatter.italic(deprecated_descr)
                    else:
                        descr = self.formatter.italic(deprecated_descr)

                if profile_mode and profile_mode != 'subset':
                    profile_spec = ''
                    if enum_name in profile_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_min_support_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_parameter_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_recommended_values:
                        profile_spec = 'Recommended'
                    contents.append('| ' + enum_name + ' | ' + descr + ' | ' +
                                    profile_spec + ' |')
                else:
                    contents.append('| ' + enum_name + ' | ' + descr + ' |')

        elif enum:
            if profile_mode and profile_mode != 'subset':
                contents.append('| ' + prop_type + ' | Profile Specifies |')
                contents.append('| --- | --- |')
            else:
                contents.append('| ' + prop_type + ' |')
                contents.append('| --- |')
            for enum_item in enum:
                enum_name = enum_item
                version = version_depr = deprecated_descr = None
                version_display = None

                if parent_prop_info.get('enumVersionAdded'):
                    version_added = parent_prop_info.get(
                        'enumVersionAdded').get(enum_name)
                    if version_added:
                        version = self.format_version(version_added)

                if parent_prop_info('enumVersionDeprecated'):
                    version_deprecated = parent_prop_info.get(
                        'enumVersionDeprecated').get(enum_name)
                    if version_deprecated:
                        version_depr = self.format_version(version_deprecated)

                if parent_prop_info.get('enumDeprecated'):
                    deprecated_descr = parent_prop_info.get(
                        'enumDeprecated').get(enum_name)

                if version:
                    if not parent_version or DocGenUtilities.compare_versions(
                            version, parent_version) > 0:
                        version_text = html.escape(version, False)
                        version_display = self.truncate_version(
                            version_text, 2) + '+'

                if version_display:
                    if version_depr:
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        if deprecated_descr:
                            enum_name += ' ' + self.formatter.italic(
                                '(v' + version_display + ', deprecated v' +
                                deprecated_display + '+. ' + deprecated_descr)
                        else:
                            enum_name += ' ' + self.formatter.italic(
                                '(v' + version_display + ', deprecated v' +
                                deprecated_display + ')')

                    else:
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ')')
                else:
                    if version_depr:
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        if deprecated_descr:
                            enum_name += ' ' + self.formatter.italic(
                                'Deprecated in v' + deprecated_display +
                                ' and later. ' + deprecated_descr)
                        else:
                            enum_name += ' ' + self.formatter.italic(
                                '(deprecated in v' + deprecated_display +
                                ' and later.)')

                if profile_mode and profile_mode != 'subset':
                    profile_spec = ''
                    if enum_name in profile_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_min_support_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_parameter_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_recommended_values:
                        profile_spec = 'Recommended'

                    contents.append('| ' + enum_name + ' | ' + profile_spec +
                                    ' |')
                else:
                    contents.append('| ' + enum_name + ' | ')

        return '\n'.join(contents) + '\n'
Example #8
0
    def format_property_details(self,
                                prop_name,
                                prop_type,
                                prop_description,
                                enum,
                                enum_details,
                                supplemental_details,
                                meta,
                                anchor=None,
                                profile=None):
        """Generate a formatted table of enum information for inclusion in Property Details."""

        contents = []
        contents.append(self.formatter.head_three(prop_name + ':', self.level))

        parent_version = meta.get('version')
        enum_meta = meta.get('enum', {})

        # Are we in profile mode? If so, consult the profile passed in for this property.
        # For Action Parameters, look for ParameterValues/RecommendedValues; for
        # Property enums, look for MinSupportValues/RecommendedValues.
        profile_mode = self.config.get('profile_mode')
        if profile_mode:
            if profile is None:
                profile = {}

            profile_values = profile.get('Values', [])
            profile_min_support_values = profile.get('MinSupportValues', [])
            profile_parameter_values = profile.get('ParameterValues', [])
            profile_recommended_values = profile.get('RecommendedValues', [])

            profile_all_values = (profile_values + profile_min_support_values +
                                  profile_parameter_values +
                                  profile_recommended_values)

        if prop_description:
            contents.append(
                self.formatter.para(
                    self.escape_for_markdown(
                        prop_description, self.config.get('escape_chars',
                                                          []))))

        if isinstance(prop_type, list):
            prop_type = ', '.join(prop_type)

        if supplemental_details:
            contents.append('\n' + supplemental_details + '\n')

        if enum_details:
            if profile_mode:
                contents.append('| ' + prop_type +
                                ' | Description | Profile Specifies |')
                contents.append('| --- | --- | --- |')
            else:
                contents.append('| ' + prop_type + ' | Description |')
                contents.append('| --- | --- |')
            enum.sort(key=str.lower)
            for enum_item in enum:
                enum_name = enum_item
                enum_item_meta = enum_meta.get(enum_item, {})
                version_display = None
                deprecated_descr = None
                if 'version' in enum_item_meta:
                    version = enum_item_meta['version']
                    if not parent_version or DocGenUtilities.compare_versions(
                            version, parent_version) > 0:
                        version_display = self.truncate_version(version,
                                                                2) + '+'
                if version_display:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = enum_item_meta['version_deprecated']
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ', deprecated v' +
                            deprecated_display + ')')
                        if enum_item_meta.get(
                                'version_deprecated_explanation'):
                            deprecated_descr = (
                                "Deprecated v" + deprecated_display + '+. ' +
                                enum_item_meta[
                                    'version_deprecated_explanation'])
                    else:
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ')')
                else:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = enum_item_meta['version_deprecated']
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        enum_name += ' ' + self.formatter.italic(
                            '(deprecated v' + deprecated_display + ')')
                        if enum_item_meta.get(
                                'version_deprecated_explanation'):
                            deprecated_descr = (
                                "Deprecated v" + deprecated_display + '+. ' +
                                enum_item_meta[
                                    'version_deprecated_explanation'])
                descr = enum_details.get(enum_item, '')
                if deprecated_descr:
                    if descr:
                        descr += ' ' + self.formatter.italic(deprecated_descr)
                    else:
                        descr = self.formatter.italic(deprecated_descr)

                if profile_mode:
                    profile_spec = ''
                    if enum_name in profile_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_min_support_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_parameter_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_recommended_values:
                        profile_spec = 'Recommended'
                    contents.append('| ' + enum_name + ' | ' + descr + ' | ' +
                                    profile_spec + ' |')
                else:
                    contents.append('| ' + enum_name + ' | ' + descr + ' |')

        elif enum:
            if profile_mode:
                contents.append('| ' + prop_type + ' | Profile Specifies |')
                contents.append('| --- | --- |')
            else:
                contents.append('| ' + prop_type + ' |')
                contents.append('| --- |')
            for enum_item in enum:
                enum_name = enum_item
                enum_item_meta = enum_meta.get(enum_item, {})
                version_display = None

                if 'version' in enum_item_meta:
                    version = enum_item_meta['version']
                    if not parent_version or DocGenUtilities.compare_versions(
                            version, parent_version) > 0:
                        version_display = self.truncate_version(version,
                                                                2) + '+'
                if version_display:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = enum_item_meta['version_deprecated']
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ', deprecated v' +
                            deprecated_display + ')')
                        if enum_item_meta.get(
                                'version_deprecated_explanation'):
                            deprecated_descr = (
                                'Deprecated v' + deprecated_display + '+. ' +
                                enum_item_meta[
                                    'version_deprecated_explanation'])
                    else:
                        enum_name += ' ' + self.formatter.italic(
                            '(v' + version_display + ')')
                else:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = enum_item_meta['version_deprecated']
                        deprecated_display = self.truncate_version(
                            version_depr, 2)
                        enum_name += ' ' + self.formatter.italic(
                            '(deprecated v' + deprecated_display + ')')
                        if enum_item_meta.get(
                                'version_deprecated_explanation'):
                            enum_name += ' ' + self.formatter.italic(
                                'Deprecated v' + deprecated_display + '+. ' +
                                enum_item_meta['version_deprecated_explanation']
                            )

                if profile_mode:
                    profile_spec = ''
                    if enum_name in profile_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_min_support_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_parameter_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_recommended_values:
                        profile_spec = 'Recommended'

                    contents.append('| ' + enum_name + ' | ' + profile_spec +
                                    ' |')
                else:
                    contents.append('| ' + enum_name + ' | ')

        return '\n'.join(contents) + '\n'
Example #9
0
    def format_property_details(self, prop_name, prop_type, prop_description, enum, enum_details,
                                    supplemental_details, parent_prop_info, profile=None):
        """Generate a formatted table of enum information for inclusion in Property details."""

        contents = []

        parent_version = parent_prop_info.get('versionAdded')
        if parent_version:
            parent_version = self.format_version(parent_version)

        # Are we in profile mode? If so, consult the profile passed in for this property.
        # For Action Parameters, look for ParameterValues/RecommendedValues; for
        # Property enums, look for MinSupportValues/RecommendedValues.
        profile_mode = self.config.get('profile_mode')
        if profile_mode:
            if profile is None:
                profile = {}
            profile_values = profile.get('Values', [])
            profile_min_support_values = profile.get('MinSupportValues', []) # No longer a valid name?
            profile_parameter_values = profile.get('ParameterValues', [])
            profile_recommended_values = profile.get('RecommendedValues', [])

            # profile_all_values is not used. What were we going for here?
            profile_all_values = (profile_values + profile_min_support_values + profile_parameter_values
                                  + profile_recommended_values)

        # In subset mode, an action parameter with no Values (property) or ParameterValues (Action)
        # means all values are supported.
        # Otherwise, Values/ParameterValues specifies the set that should be listed.
        if profile_mode == 'subset':
            if len(profile_values):
                enum = [x for x in enum if x in profile_values]
            elif len(profile_parameter_values):
                enum = [x for x in enum if x in profile_parameter_values]

        if prop_description:
            contents.append(self.formatter.para(prop_description))

        if isinstance(prop_type, list):
            prop_type = ', '.join([html.escape(x, False) for x in prop_type])
        else:
            prop_type = html.escape(prop_type, False)

        if supplemental_details:
            contents.append(self.formatter.markdown_to_html(supplemental_details))

        if enum_details:
            headings = [prop_type, 'Description']
            if profile_mode and profile_mode != 'subset':
                headings.append('Profile Specifies')
            header_row = self.formatter.make_header_row(headings)
            table_rows = []
            enum.sort(key=str.lower)

            for enum_item in enum:
                enum_name = html.escape(enum_item, False)
                version = version_depr = deprecated_descr = None
                version_display = None
                if parent_prop_info.get('enumVersionAdded'):
                    version_added = parent_prop_info.get('enumVersionAdded').get(enum_name)
                    if version_added:
                        version = self.format_version(version_added)
                if parent_prop_info.get('enumVersionDeprecated'):
                    version_deprecated = parent_prop_info.get('enumVersionDeprecated').get(enum_name)
                    if version_deprecated:
                        version_depr = self.format_version(version_deprecated)
                if parent_prop_info.get('enumDeprecated'):
                    deprecated_descr = parent_prop_info.get('enumDeprecated').get(enum_name)

                if version:
                    if not parent_version or DocGenUtilities.compare_versions(version, parent_version) > 0:
                        version_text = html.escape(version, False)
                        version_display = self.truncate_version(version_text, 2) + '+'

                if version_display:
                    if version_depr:
                        version_depr_text = html.escape(version_depr, False)
                        deprecated_display = self.truncate_version(version_depr_text, 2)
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ', deprecated v' + deprecated_display + ')')
                        if deprecated_descr:
                            deprecated_descr_text = html.escape('Deprecated in v' + deprecated_display
                                                                    + ' and later. ' + deprecated_descr)
                    else:
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ')')
                elif version_depr:
                    version_depr_text = html.escape(version_depr, False)
                    deprecated_display = self.truncate_version(version_depr_text, 2)
                    enum_name += ' ' + self.formatter.italic('(deprecated v' + deprecated_display + ')')
                    if deprecated_descr:
                        deprecated_descr_text = html.escape('Deprecated in v' + deprecated_display + ' and later. ' +
                                                        deprecated_descr)

                descr = html.escape(enum_details.get(enum_item, ''), False)
                if deprecated_descr:
                    if descr:
                        descr += ' ' + self.formatter.italic(deprecated_descr)
                    else:
                        descr = self.formatter.italic(deprecated_descr)
                cells = [enum_name, descr]

                if profile_mode and profile_mode != 'subset':
                    if enum_name in profile_values:
                        cells.append('Mandatory')
                    elif enum_name in profile_min_support_values:
                        cells.append('Mandatory')
                    elif enum_name in profile_parameter_values:
                        cells.append('Mandatory')
                    elif enum_name in profile_recommended_values:
                        cells.append('Recommended')
                    else:
                        cells.append('')

                table_rows.append(self.formatter.make_row(cells))
            contents.append(self.formatter.make_table(table_rows, [header_row], 'enum enum-details'))

        elif enum:
            headings = [prop_type]
            if profile_mode and profile_mode != 'subset':
                headings.append('Profile Specifies')
            header_row = self.formatter.make_header_row(headings)
            table_rows = []
            enum.sort(key=str.lower)
            for enum_item in enum:
                enum_name = html.escape(enum_item, False)
                version = version_depr = deprecated_descr = None
                version_display = None

                if parent_prop_info.get('enumVersionAdded'):
                    version_added = parent_prop_info.get('enumVersionAdded').get(enum_name)
                    if version_added:
                        version = self.format_version(version_added)

                if parent_prop_info('enumVersionDeprecated'):
                    version_deprecated = parent_prop_info.get('enumVersionDeprecated').get(enum_name)
                    if version_deprecated:
                        version_depr = self.format_version(version_deprecated)

                if parent_prop_info.get('enumDeprecated'):
                    deprecated_descr = parent_prop_info.get('enumDeprecated').get(enum_name)

                if version:
                    if not parent_version or DocGenUtilities.compare_versions(version, parent_version) > 0:
                        version_text = html.escape(version, False)
                        version_display = self.truncate_version(version_text, 2) + '+'

                if version_display:
                    if version_depr:
                        version_depr_text = html.escape(version_depr, False)
                        deprecated_display = self.truncate_version(version_depr_text, 2)
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ', deprecated v' + deprecated_display + ')')
                        if deprecated_descr:
                            enum_name += '<br>' + self.formatter.italic(html.escape(
                                'Deprecated in v' + deprecated_display
                                + ' and later. ' + deprecated_descr))
                    else:
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ')')

                elif version_depr:
                    version_depr_text = html.escape(version_depr, False)
                    deprecated_display = self.truncate_version(version_depr_text, 2)
                    enum_name += ' ' + self.formatter.italic('(deprecated v' + deprecated_display + ')')
                    if deprecated_descr:
                        enum_name += '<br>' + self.formatter.italic(html.escape(
                            'Deprecated in v' + deprecated_display + ' and later. ' +
                            deprecated_descr))


                cells = [enum_name]
                if profile_mode and profile_mode != 'subset':
                    if enum_name in profile_values:
                        cells.append('Mandatory')
                    elif enum_name in profile_min_support_values:
                        cells.append('Mandatory')
                    elif enum_name in profile_parameter_values:
                        cells.append('Mandatory')
                    elif enum_name in profile_recommended_values:
                        cells.append('Recommended')
                    else:
                        cells.append('')

                table_rows.append(self.formatter.make_row(cells))
            contents.append(self.formatter.make_table(table_rows, [header_row], 'enum'))

        return '\n'.join(contents) + '\n'
Example #10
0
    def format_property_details(self, prop_name, prop_type, prop_description, enum, enum_details,
                                supplemental_details, meta, anchor=None, profile=None):
        """Generate a formatted table of enum information for inclusion in Property Details."""

        contents = []
        contents.append(self.formatter.head_three(prop_name + ':', self.level))

        parent_version = meta.get('version')
        enum_meta = meta.get('enum', {})

        # Are we in profile mode? If so, consult the profile passed in for this property.
        # For Action Parameters, look for ParameterValues/RecommendedValues; for
        # Property enums, look for MinSupportValues/RecommendedValues.
        profile_mode = self.config.get('profile_mode')
        if profile_mode:
            if profile is None:
                profile = {}

            profile_values = profile.get('Values', [])
            profile_min_support_values = profile.get('MinSupportValues', [])
            profile_parameter_values = profile.get('ParameterValues', [])
            profile_recommended_values = profile.get('RecommendedValues', [])

            profile_all_values = (profile_values + profile_min_support_values + profile_parameter_values
                                  + profile_recommended_values)

        if prop_description:
            contents.append(self.formatter.para(self.escape_for_markdown(prop_description, self.config.get('escape_chars', []))))

        if isinstance(prop_type, list):
            prop_type = ', '.join(prop_type)

        if supplemental_details:
            contents.append('\n' + supplemental_details + '\n')

        if enum_details:
            if profile_mode:
                contents.append('| ' + prop_type + ' | Description | Profile Specifies |')
                contents.append('| --- | --- | --- |')
            else:
                contents.append('| ' + prop_type + ' | Description |')
                contents.append('| --- | --- |')
            enum.sort(key=str.lower)
            for enum_item in enum:
                enum_name = enum_item
                enum_item_meta = enum_meta.get(enum_item, {})
                version_display = None
                deprecated_descr = None
                if 'version' in enum_item_meta:
                    version = enum_item_meta['version']
                    if not parent_version or DocGenUtilities.compare_versions(version, parent_version) > 0:
                        version_display = self.truncate_version(version, 2) + '+'
                if version_display:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = enum_item_meta['version_deprecated']
                        deprecated_display = self.truncate_version(version_depr, 2)
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ', deprecated v' + deprecated_display + ')')
                        if enum_item_meta.get('version_deprecated_explanation'):
                            deprecated_descr = ("Deprecated v" + deprecated_display + '+. ' +
                                                enum_item_meta['version_deprecated_explanation'])
                    else:
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ')')
                else:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = enum_item_meta['version_deprecated']
                        deprecated_display = self.truncate_version(version_depr, 2)
                        enum_name += ' ' + self.formatter.italic('(deprecated v' + deprecated_display + ')')
                        if enum_item_meta.get('version_deprecated_explanation'):
                            deprecated_descr = ("Deprecated v" + deprecated_display + '+. ' +
                                                enum_item_meta['version_deprecated_explanation'])
                descr = enum_details.get(enum_item, '')
                if deprecated_descr:
                    if descr:
                        descr += ' ' + self.formatter.italic(deprecated_descr)
                    else:
                        descr = self.formatter.italic(deprecated_descr)

                if profile_mode:
                    profile_spec = ''
                    if enum_name in profile_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_min_support_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_parameter_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_recommended_values:
                        profile_spec = 'Recommended'
                    contents.append('| ' + enum_name + ' | ' + descr + ' | ' + profile_spec + ' |')
                else:
                    contents.append('| ' + enum_name + ' | ' + descr + ' |')

        elif enum:
            if profile_mode:
                contents.append('| ' + prop_type + ' | Profile Specifies |')
                contents.append('| --- | --- |')
            else:
                contents.append('| ' + prop_type + ' |')
                contents.append('| --- |')
            for enum_item in enum:
                enum_name = enum_item
                enum_item_meta = enum_meta.get(enum_item, {})
                version_display = None

                if 'version' in enum_item_meta:
                    version = enum_item_meta['version']
                    if not parent_version or DocGenUtilities.compare_versions(version, parent_version) > 0:
                        version_display = self.truncate_version(version, 2) + '+'
                if version_display:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = enum_item_meta['version_deprecated']
                        deprecated_display = self.truncate_version(version_depr, 2)
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ', deprecated v' + deprecated_display + ')')
                        if enum_item_meta.get('version_deprecated_explanation'):
                            deprecated_descr = ('Deprecated v' + deprecated_display + '+. ' +
                                                enum_item_meta['version_deprecated_explanation'])
                    else:
                        enum_name += ' ' + self.formatter.italic('(v' + version_display + ')')
                else:
                    if 'version_deprecated' in enum_item_meta:
                        version_depr = enum_item_meta['version_deprecated']
                        deprecated_display = self.truncate_version(version_depr, 2)
                        enum_name += ' ' + self.formatter.italic('(deprecated v' + deprecated_display + ')')
                        if enum_item_meta.get('version_deprecated_explanation'):
                            enum_name += ' ' + self.formatter.italic('Deprecated v' + deprecated_display + '+. ' +
                                                           enum_item_meta['version_deprecated_explanation'])

                if profile_mode:
                    profile_spec = ''
                    if enum_name in profile_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_min_support_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_parameter_values:
                        profile_spec = 'Required'
                    elif enum_name in profile_recommended_values:
                        profile_spec = 'Recommended'

                    contents.append('| ' + enum_name + ' | ' + profile_spec + ' |')
                else:
                    contents.append('| ' + enum_name + ' | ')

        return '\n'.join(contents) + '\n'