deno_doc 0.198.0

doc generation for deno
Documentation
use crate::Declaration;
use crate::r#enum::EnumMemberDef;
use crate::html::DiffStatus;
use crate::html::DocNodeWithContext;
use crate::html::render_context::RenderContext;
use crate::html::types::render_type_def;
use crate::html::util::*;
use crate::js_doc::JsDocTag;

pub(crate) fn render_enum(
  render_ctx: &RenderContext,
  symbol: &DocNodeWithContext,
  decl: &Declaration,
) -> Vec<SectionCtx> {
  let enum_def = decl.enum_def().unwrap();

  let enum_diff = render_ctx.ctx.diff.as_ref().and_then(|diff_index| {
    diff_index
      .get_def_diff(
        &symbol.origin.specifier,
        symbol.get_name(),
        decl.def.to_kind(),
      )
      .and_then(|d| d.as_enum())
  });

  let mut members = enum_def.members.clone();
  members.sort_by(|a, b| {
    let is_deprecated = |m: &EnumMemberDef| {
      m.js_doc
        .tags
        .iter()
        .any(|t| matches!(t, JsDocTag::Deprecated { .. }))
    };

    is_deprecated(a)
      .cmp(&is_deprecated(b))
      .then_with(|| a.name.cmp(&b.name))
  });

  let mut items = members
    .into_iter()
    .map(|member| {
      let id = IdBuilder::new(render_ctx)
        .kind(IdKind::Enum)
        .name(symbol.get_name())
        .name(&member.name)
        .build();

      let tags = Tag::from_js_doc(&member.js_doc);

      let diff_status = if let Some(diff) = enum_diff {
        if diff.added_members.iter().any(|m| m.name == member.name) {
          Some(DiffStatus::Added)
        } else if diff.modified_members.iter().any(|m| m.name == member.name) {
          Some(DiffStatus::Modified)
        } else {
          None
        }
      } else {
        None
      };

      let (old_content, old_tags, member_diff) =
        if matches!(diff_status, Some(DiffStatus::Modified)) {
          let member_diff = enum_diff.and_then(|d| {
            d.modified_members.iter().find(|m| m.name == member.name)
          });
          let old_content = member_diff
            .and_then(|md| md.init_change.as_ref())
            .map(|tc| format!(" = {}", render_type_def(render_ctx, &tc.old)));
          let old_tags =
            Some(super::compute_old_tags(&tags, None, None, None, None));
          (old_content, old_tags, member_diff)
        } else {
          (None, None, None)
        };

      DocEntryCtx::new(
        render_ctx,
        id,
        Some(html_escape::encode_text(&member.name).into_owned()),
        None,
        &member
          .init
          .as_ref()
          .map(|init| format!(" = {}", render_type_def(render_ctx, init)))
          .unwrap_or_default(),
        tags,
        member.js_doc.doc.as_deref(),
        &member.location,
        diff_status,
        old_content,
        old_tags,
        member_diff.and_then(|md| md.js_doc_change.as_ref()),
      )
    })
    .collect::<Vec<DocEntryCtx>>();

  // Inject removed members
  if let Some(enum_diff) = enum_diff {
    for removed_member in &enum_diff.removed_members {
      let id = IdBuilder::new(render_ctx)
        .kind(IdKind::Enum)
        .name(symbol.get_name())
        .name(&removed_member.name)
        .build();

      let tags = Tag::from_js_doc(&removed_member.js_doc);

      items.push(DocEntryCtx::removed(
        render_ctx,
        id,
        Some(html_escape::encode_text(&removed_member.name).into_owned()),
        None,
        &removed_member
          .init
          .as_ref()
          .map(|init| format!(" = {}", render_type_def(render_ctx, init)))
          .unwrap_or_default(),
        tags,
        removed_member.js_doc.doc.as_deref(),
        &removed_member.location,
      ));
    }
  }

  vec![SectionCtx::new(
    render_ctx,
    "Members",
    SectionContentCtx::DocEntry(items),
  )]
}