docs: def render_html(data_dir, output_dir):
      """
      The main workhorse of this script. Finds all the JSON data files
      from pa11ycrawler, and transforms them into HTML files via Jinja2 templating.
      """
      env = Environment(loader=PackageLoader('pa11ycrawler', 'templates'))
      env.globals["wcag_refs"] = wcag_refs
      pages = []
      counter = collections.Counter()
      grouped_violations = collections.defaultdict(dict)
  
      # render detail templates
      for data_file in data_dir.files('*.json'):
          data = json.load(data_file.open())
          num_error, num_warning, num_notice = pa11y_counts(data['pa11y'])
  
          data["num_error"] = num_error
          data["num_warning"] = num_warning
          data["num_notice"] = num_notice
          fname = data_file.namebase + ".html"
          html_path = output_dir / fname
          render_template(env, html_path, 'detail.html', data)
  
          data["filename"] = fname
          pages.append(data)
  
          for violation in data['pa11y']:
              violation_id = hashlib.md5(
                  (violation['selector'] + violation['code']).encode('utf-8')
              ).hexdigest()
  
              if violation_id not in grouped_violations[violation['type']]:
                  violation['pages'] = []
                  grouped_violations[violation['type']][violation_id] = violation
                  counter[violation['type']] += 1
  
              grouped_violations[violation['type']][violation_id]['pages'].append({
                  'url': data['url'],
                  'page_title': data['page_title']
              })
  
      def extract_nums(page):
          "Used to sort pages by violation counts"
          return (
              page["num_error"],
              page["num_warning"],
              page["num_notice"],
          )
  
      index_path = output_dir / INDEX_TEMPLATE
      render_template(env, index_path, INDEX_TEMPLATE, {
          "pages": sorted(pages, key=extract_nums, reverse=True),
          "num_error": counter["error"],
          "num_warning": counter["warning"],
          "num_notice": counter["notice"]
      })
  
      for violation_type in grouped_violations:
          unique_path = output_dir / u'{}s.html'.format(violation_type)
          render_template(env, unique_path, UNIQUE_TEMPLATE, {
              "grouped_violations": sorted(
                  grouped_violations[violation_type].values(),
                  key=lambda item: len(item['pages']),
                  reverse=True
              ),
              "current_type": violation_type,
              "violation_counts": counter
          })