commonmarker 0.23.1 → 0.23.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of commonmarker might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Rakefile +56 -55
- data/bin/commonmarker +2 -7
- data/commonmarker.gemspec +27 -26
- data/ext/commonmarker/blocks.c +13 -2
- data/ext/commonmarker/cmark-gfm_version.h +2 -2
- data/ext/commonmarker/commonmark.c +14 -4
- data/ext/commonmarker/commonmarker.c +30 -44
- data/ext/commonmarker/ext_scanners.c +360 -640
- data/ext/commonmarker/footnotes.c +23 -0
- data/ext/commonmarker/footnotes.h +2 -0
- data/ext/commonmarker/html.c +40 -19
- data/ext/commonmarker/inlines.c +69 -11
- data/ext/commonmarker/node.h +7 -0
- data/ext/commonmarker/scanners.c +2438 -2450
- data/ext/commonmarker/table.c +98 -53
- data/lib/commonmarker/config.rb +1 -1
- data/lib/commonmarker/node/inspect.rb +8 -18
- data/lib/commonmarker/node.rb +6 -6
- data/lib/commonmarker/renderer/html_renderer.rb +37 -37
- data/lib/commonmarker/renderer.rb +5 -5
- data/lib/commonmarker/version.rb +1 -1
- data/lib/commonmarker.rb +9 -11
- metadata +6 -57
- data/test/benchmark.rb +0 -32
- data/test/fixtures/curly.md +0 -1
- data/test/fixtures/dingus.md +0 -10
- data/test/fixtures/strong.md +0 -1
- data/test/fixtures/table.md +0 -10
- data/test/test_attributes.rb +0 -24
- data/test/test_basics.rb +0 -35
- data/test/test_commands.rb +0 -72
- data/test/test_commonmark.rb +0 -36
- data/test/test_doc.rb +0 -130
- data/test/test_encoding.rb +0 -23
- data/test/test_extensions.rb +0 -116
- data/test/test_footnotes.rb +0 -48
- data/test/test_gc.rb +0 -47
- data/test/test_helper.rb +0 -71
- data/test/test_linebreaks.rb +0 -15
- data/test/test_maliciousness.rb +0 -262
- data/test/test_node.rb +0 -89
- data/test/test_options.rb +0 -37
- data/test/test_pathological_inputs.rb +0 -94
- data/test/test_plaintext.rb +0 -46
- data/test/test_renderer.rb +0 -47
- data/test/test_smartpunct.rb +0 -27
- data/test/test_spec.rb +0 -30
- data/test/test_tasklists.rb +0 -43
- data/test/test_xml.rb +0 -107
    
        data/ext/commonmarker/table.c
    CHANGED
    
    | @@ -114,60 +114,94 @@ static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsi | |
| 114 114 | 
             
            static table_row *row_from_string(cmark_syntax_extension *self,
         | 
| 115 115 | 
             
                                              cmark_parser *parser, unsigned char *string,
         | 
| 116 116 | 
             
                                              int len) {
         | 
| 117 | 
            +
              // Parses a single table row. It has the following form:
         | 
| 118 | 
            +
              // `delim? table_cell (delim table_cell)* delim? newline`
         | 
| 119 | 
            +
              // Note that cells are allowed to be empty.
         | 
| 120 | 
            +
              //
         | 
| 121 | 
            +
              // From the GitHub-flavored Markdown specification:
         | 
| 122 | 
            +
              //
         | 
| 123 | 
            +
              // > Each row consists of cells containing arbitrary text, in which inlines
         | 
| 124 | 
            +
              // > are parsed, separated by pipes (|). A leading and trailing pipe is also
         | 
| 125 | 
            +
              // > recommended for clarity of reading, and if there’s otherwise parsing
         | 
| 126 | 
            +
              // > ambiguity.
         | 
| 127 | 
            +
             | 
| 117 128 | 
             
              table_row *row = NULL;
         | 
| 118 129 | 
             
              bufsize_t cell_matched = 1, pipe_matched = 1, offset;
         | 
| 119 | 
            -
              int  | 
| 130 | 
            +
              int expect_more_cells = 1;
         | 
| 131 | 
            +
              int row_end_offset = 0;
         | 
| 132 | 
            +
              int int_overflow_abort = 0;
         | 
| 120 133 |  | 
| 121 134 | 
             
              row = (table_row *)parser->mem->calloc(1, sizeof(table_row));
         | 
| 122 135 | 
             
              row->n_columns = 0;
         | 
| 123 136 | 
             
              row->cells = NULL;
         | 
| 124 137 |  | 
| 138 | 
            +
              // Scan past the (optional) leading pipe.
         | 
| 125 139 | 
             
              offset = scan_table_cell_end(string, len, 0);
         | 
| 126 140 |  | 
| 127 141 | 
             
              // Parse the cells of the row. Stop if we reach the end of the input, or if we
         | 
| 128 142 | 
             
              // cannot detect any more cells.
         | 
| 129 | 
            -
              while (offset < len &&  | 
| 143 | 
            +
              while (offset < len && expect_more_cells) {
         | 
| 130 144 | 
             
                cell_matched = scan_table_cell(string, len, offset);
         | 
| 131 145 | 
             
                pipe_matched = scan_table_cell_end(string, len, offset + cell_matched);
         | 
| 132 146 |  | 
| 133 147 | 
             
                if (cell_matched || pipe_matched) {
         | 
| 134 | 
            -
                   | 
| 148 | 
            +
                  // We are guaranteed to have a cell, since (1) either we found some
         | 
| 149 | 
            +
                  // content and cell_matched, or (2) we found an empty cell followed by a
         | 
| 150 | 
            +
                  // pipe.
         | 
| 151 | 
            +
                  cmark_strbuf *cell_buf = unescape_pipes(parser->mem, string + offset,
         | 
| 152 | 
            +
                      cell_matched);
         | 
| 153 | 
            +
                  cmark_strbuf_trim(cell_buf);
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                  node_cell *cell = (node_cell *)parser->mem->calloc(1, sizeof(*cell));
         | 
| 156 | 
            +
                  cell->buf = cell_buf;
         | 
| 157 | 
            +
                  cell->start_offset = offset;
         | 
| 158 | 
            +
                  cell->end_offset = offset + cell_matched - 1;
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                  while (cell->start_offset > 0 && string[cell->start_offset - 1] != '|') {
         | 
| 161 | 
            +
                    --cell->start_offset;
         | 
| 162 | 
            +
                    ++cell->internal_offset;
         | 
| 163 | 
            +
                  }
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                  // make sure we never wrap row->n_columns
         | 
| 166 | 
            +
                  // offset will != len and our exit will clean up as intended
         | 
| 167 | 
            +
                  if (row->n_columns == UINT16_MAX) {
         | 
| 168 | 
            +
                      int_overflow_abort = 1;
         | 
| 169 | 
            +
                      break;
         | 
| 170 | 
            +
                  }
         | 
| 171 | 
            +
                  row->n_columns += 1;
         | 
| 172 | 
            +
                  row->cells = cmark_llist_append(parser->mem, row->cells, cell);
         | 
| 173 | 
            +
                }
         | 
| 135 174 |  | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 175 | 
            +
                offset += cell_matched + pipe_matched;
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                if (pipe_matched) {
         | 
| 178 | 
            +
                  expect_more_cells = 1;
         | 
| 179 | 
            +
                } else {
         | 
| 180 | 
            +
                  // We've scanned the last cell. Check if we have reached the end of the row
         | 
| 181 | 
            +
                  row_end_offset = scan_table_row_end(string, len, offset);
         | 
| 182 | 
            +
                  offset += row_end_offset;
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                  // If the end of the row is not the end of the input,
         | 
| 185 | 
            +
                  // the row is not a real row but potentially part of the paragraph
         | 
| 186 | 
            +
                  // preceding the table.
         | 
| 187 | 
            +
                  if (row_end_offset && offset != len) {
         | 
| 188 | 
            +
                    row->paragraph_offset = offset;
         | 
| 138 189 |  | 
| 139 190 | 
             
                    cmark_llist_free_full(parser->mem, row->cells, (cmark_free_func)free_table_cell);
         | 
| 140 191 | 
             
                    row->cells = NULL;
         | 
| 141 192 | 
             
                    row->n_columns = 0;
         | 
| 142 | 
            -
                  } else {
         | 
| 143 | 
            -
                    cmark_strbuf *cell_buf = unescape_pipes(parser->mem, string + offset,
         | 
| 144 | 
            -
                        cell_matched);
         | 
| 145 | 
            -
                    cmark_strbuf_trim(cell_buf);
         | 
| 146 | 
            -
             | 
| 147 | 
            -
                    node_cell *cell = (node_cell *)parser->mem->calloc(1, sizeof(*cell));
         | 
| 148 | 
            -
                    cell->buf = cell_buf;
         | 
| 149 | 
            -
                    cell->start_offset = offset;
         | 
| 150 | 
            -
                    cell->end_offset = cell_end_offset;
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                    while (cell->start_offset > 0 && string[cell->start_offset - 1] != '|') {
         | 
| 153 | 
            -
                      --cell->start_offset;
         | 
| 154 | 
            -
                      ++cell->internal_offset;
         | 
| 155 | 
            -
                    }
         | 
| 156 193 |  | 
| 157 | 
            -
                     | 
| 158 | 
            -
                     | 
| 159 | 
            -
                  }
         | 
| 160 | 
            -
                }
         | 
| 161 | 
            -
             | 
| 162 | 
            -
                offset += cell_matched + pipe_matched;
         | 
| 194 | 
            +
                    // Scan past the (optional) leading pipe.
         | 
| 195 | 
            +
                    offset += scan_table_cell_end(string, len, offset);
         | 
| 163 196 |  | 
| 164 | 
            -
             | 
| 165 | 
            -
                   | 
| 166 | 
            -
             | 
| 197 | 
            +
                    expect_more_cells = 1;
         | 
| 198 | 
            +
                  } else {
         | 
| 199 | 
            +
                    expect_more_cells = 0;
         | 
| 200 | 
            +
                  }
         | 
| 167 201 | 
             
                }
         | 
| 168 202 | 
             
              }
         | 
| 169 203 |  | 
| 170 | 
            -
              if (offset != len ||  | 
| 204 | 
            +
              if (offset != len || row->n_columns == 0 || int_overflow_abort) {
         | 
| 171 205 | 
             
                free_table_row(parser->mem, row);
         | 
| 172 206 | 
             
                row = NULL;
         | 
| 173 207 | 
             
              }
         | 
| @@ -199,8 +233,6 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self, | |
| 199 233 | 
             
                                                        cmark_parser *parser,
         | 
| 200 234 | 
             
                                                        cmark_node *parent_container,
         | 
| 201 235 | 
             
                                                        unsigned char *input, int len) {
         | 
| 202 | 
            -
              bufsize_t matched =
         | 
| 203 | 
            -
                  scan_table_start(input, len, cmark_parser_get_first_nonspace(parser));
         | 
| 204 236 | 
             
              cmark_node *table_header;
         | 
| 205 237 | 
             
              table_row *header_row = NULL;
         | 
| 206 238 | 
             
              table_row *marker_row = NULL;
         | 
| @@ -208,41 +240,48 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self, | |
| 208 240 | 
             
              const char *parent_string;
         | 
| 209 241 | 
             
              uint16_t i;
         | 
| 210 242 |  | 
| 211 | 
            -
              if (! | 
| 212 | 
            -
                return parent_container;
         | 
| 213 | 
            -
             | 
| 214 | 
            -
              parent_string = cmark_node_get_string_content(parent_container);
         | 
| 215 | 
            -
             | 
| 216 | 
            -
              cmark_arena_push();
         | 
| 217 | 
            -
             | 
| 218 | 
            -
              header_row = row_from_string(self, parser, (unsigned char *)parent_string,
         | 
| 219 | 
            -
                                           (int)strlen(parent_string));
         | 
| 220 | 
            -
             | 
| 221 | 
            -
              if (!header_row) {
         | 
| 222 | 
            -
                free_table_row(parser->mem, header_row);
         | 
| 223 | 
            -
                cmark_arena_pop();
         | 
| 243 | 
            +
              if (!scan_table_start(input, len, cmark_parser_get_first_nonspace(parser))) {
         | 
| 224 244 | 
             
                return parent_container;
         | 
| 225 245 | 
             
              }
         | 
| 226 246 |  | 
| 247 | 
            +
              // Since scan_table_start was successful, we must have a marker row.
         | 
| 227 248 | 
             
              marker_row = row_from_string(self, parser,
         | 
| 228 249 | 
             
                                           input + cmark_parser_get_first_nonspace(parser),
         | 
| 229 250 | 
             
                                           len - cmark_parser_get_first_nonspace(parser));
         | 
| 230 | 
            -
             | 
| 251 | 
            +
              // assert may be optimized out, don't rely on it for security boundaries
         | 
| 252 | 
            +
              if (!marker_row) {
         | 
| 253 | 
            +
                  return parent_container;
         | 
| 254 | 
            +
              }
         | 
| 255 | 
            +
              
         | 
| 231 256 | 
             
              assert(marker_row);
         | 
| 232 257 |  | 
| 233 | 
            -
               | 
| 234 | 
            -
             | 
| 258 | 
            +
              cmark_arena_push();
         | 
| 259 | 
            +
             | 
| 260 | 
            +
              // Check for a matching header row. We call `row_from_string` with the entire
         | 
| 261 | 
            +
              // (potentially long) parent container as input, but this should be safe since
         | 
| 262 | 
            +
              // `row_from_string` bails out early if it does not find a row.
         | 
| 263 | 
            +
              parent_string = cmark_node_get_string_content(parent_container);
         | 
| 264 | 
            +
              header_row = row_from_string(self, parser, (unsigned char *)parent_string,
         | 
| 265 | 
            +
                                           (int)strlen(parent_string));
         | 
| 266 | 
            +
              if (!header_row || header_row->n_columns != marker_row->n_columns) {
         | 
| 235 267 | 
             
                free_table_row(parser->mem, marker_row);
         | 
| 268 | 
            +
                free_table_row(parser->mem, header_row);
         | 
| 236 269 | 
             
                cmark_arena_pop();
         | 
| 237 270 | 
             
                return parent_container;
         | 
| 238 271 | 
             
              }
         | 
| 239 272 |  | 
| 240 273 | 
             
              if (cmark_arena_pop()) {
         | 
| 274 | 
            +
                marker_row = row_from_string(
         | 
| 275 | 
            +
                    self, parser, input + cmark_parser_get_first_nonspace(parser),
         | 
| 276 | 
            +
                    len - cmark_parser_get_first_nonspace(parser));
         | 
| 241 277 | 
             
                header_row = row_from_string(self, parser, (unsigned char *)parent_string,
         | 
| 242 278 | 
             
                                             (int)strlen(parent_string));
         | 
| 243 | 
            -
                 | 
| 244 | 
            -
             | 
| 245 | 
            -
             | 
| 279 | 
            +
                // row_from_string can return NULL, add additional check to ensure n_columns match
         | 
| 280 | 
            +
                if (!marker_row || !header_row || header_row->n_columns != marker_row->n_columns) {
         | 
| 281 | 
            +
                    free_table_row(parser->mem, marker_row);
         | 
| 282 | 
            +
                    free_table_row(parser->mem, header_row);
         | 
| 283 | 
            +
                    return parent_container;
         | 
| 284 | 
            +
                }
         | 
| 246 285 | 
             
              }
         | 
| 247 286 |  | 
| 248 287 | 
             
              if (!cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) {
         | 
| @@ -257,13 +296,13 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self, | |
| 257 296 | 
             
              }
         | 
| 258 297 |  | 
| 259 298 | 
             
              cmark_node_set_syntax_extension(parent_container, self);
         | 
| 260 | 
            -
             | 
| 261 299 | 
             
              parent_container->as.opaque = parser->mem->calloc(1, sizeof(node_table));
         | 
| 262 | 
            -
             | 
| 263 300 | 
             
              set_n_table_columns(parent_container, header_row->n_columns);
         | 
| 264 301 |  | 
| 302 | 
            +
              // allocate alignments based on marker_row->n_columns
         | 
| 303 | 
            +
              // since we populate the alignments array based on marker_row->cells
         | 
| 265 304 | 
             
              uint8_t *alignments =
         | 
| 266 | 
            -
                  (uint8_t *)parser->mem->calloc( | 
| 305 | 
            +
                  (uint8_t *)parser->mem->calloc(marker_row->n_columns, sizeof(uint8_t));
         | 
| 267 306 | 
             
              cmark_llist *it = marker_row->cells;
         | 
| 268 307 | 
             
              for (i = 0; it; it = it->next, ++i) {
         | 
| 269 308 | 
             
                node_cell *node = (node_cell *)it->data;
         | 
| @@ -332,6 +371,12 @@ static cmark_node *try_opening_table_row(cmark_syntax_extension *self, | |
| 332 371 | 
             
              row = row_from_string(self, parser, input + cmark_parser_get_first_nonspace(parser),
         | 
| 333 372 | 
             
                  len - cmark_parser_get_first_nonspace(parser));
         | 
| 334 373 |  | 
| 374 | 
            +
              if (!row) {
         | 
| 375 | 
            +
                  // clean up the dangling node
         | 
| 376 | 
            +
                  cmark_node_free(table_row_block);
         | 
| 377 | 
            +
                  return NULL;
         | 
| 378 | 
            +
              }
         | 
| 379 | 
            +
             | 
| 335 380 | 
             
              {
         | 
| 336 381 | 
             
                cmark_llist *tmp;
         | 
| 337 382 | 
             
                int i, table_columns = get_n_table_columns(parent_container);
         | 
    
        data/lib/commonmarker/config.rb
    CHANGED
    
    | @@ -30,7 +30,7 @@ module CommonMarker | |
| 30 30 | 
             
                    TABLE_PREFER_STYLE_ATTRIBUTES: (1 << 15),
         | 
| 31 31 | 
             
                    FULL_INFO_STRING: (1 << 16),
         | 
| 32 32 | 
             
                  }.freeze,
         | 
| 33 | 
            -
                  format:  | 
| 33 | 
            +
                  format: [:html, :xml, :commonmark, :plaintext].freeze,
         | 
| 34 34 | 
             
                }.freeze
         | 
| 35 35 |  | 
| 36 36 | 
             
                def self.process_options(option, type)
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require  | 
| 3 | 
            +
            require "pp"
         | 
| 4 4 |  | 
| 5 5 | 
             
            module CommonMarker
         | 
| 6 6 | 
             
              class Node
         | 
| @@ -8,33 +8,23 @@ module CommonMarker | |
| 8 8 | 
             
                  PP_INDENT_SIZE = 2
         | 
| 9 9 |  | 
| 10 10 | 
             
                  def inspect
         | 
| 11 | 
            -
                    PP.pp(self, + | 
| 11 | 
            +
                    PP.pp(self, +"", Float::INFINITY)
         | 
| 12 12 | 
             
                  end
         | 
| 13 13 |  | 
| 14 14 | 
             
                  # @param printer [PrettyPrint] pp
         | 
| 15 15 | 
             
                  def pretty_print(printer)
         | 
| 16 | 
            -
                    printer.group(PP_INDENT_SIZE, "#<#{self.class}(#{type}):",  | 
| 16 | 
            +
                    printer.group(PP_INDENT_SIZE, "#<#{self.class}(#{type}):", ">") do
         | 
| 17 17 | 
             
                      printer.breakable
         | 
| 18 18 |  | 
| 19 | 
            -
                      attrs =  | 
| 20 | 
            -
                        sourcepos
         | 
| 21 | 
            -
                        string_content
         | 
| 22 | 
            -
                        url
         | 
| 23 | 
            -
                        title
         | 
| 24 | 
            -
                        header_level
         | 
| 25 | 
            -
                        list_type
         | 
| 26 | 
            -
                        list_start
         | 
| 27 | 
            -
                        list_tight
         | 
| 28 | 
            -
                        fence_info
         | 
| 29 | 
            -
                      ].map do |name|
         | 
| 19 | 
            +
                      attrs = [:sourcepos, :string_content, :url, :title, :header_level, :list_type, :list_start, :list_tight, :fence_info].map do |name|
         | 
| 30 20 | 
             
                        [name, __send__(name)]
         | 
| 31 21 | 
             
                      rescue NodeError
         | 
| 32 22 | 
             
                        nil
         | 
| 33 23 | 
             
                      end.compact
         | 
| 34 24 |  | 
| 35 25 | 
             
                      printer.seplist(attrs) do |name, value|
         | 
| 36 | 
            -
                        printer.text | 
| 37 | 
            -
                        printer.pp | 
| 26 | 
            +
                        printer.text("#{name}=")
         | 
| 27 | 
            +
                        printer.pp(value)
         | 
| 38 28 | 
             
                      end
         | 
| 39 29 |  | 
| 40 30 | 
             
                      if first_child
         | 
| @@ -46,8 +36,8 @@ module CommonMarker | |
| 46 36 | 
             
                            children << node
         | 
| 47 37 | 
             
                            node = node.next
         | 
| 48 38 | 
             
                          end
         | 
| 49 | 
            -
                          printer.text | 
| 50 | 
            -
                          printer.pp | 
| 39 | 
            +
                          printer.text("children=")
         | 
| 40 | 
            +
                          printer.pp(children)
         | 
| 51 41 | 
             
                        end
         | 
| 52 42 | 
             
                      end
         | 
| 53 43 | 
             
                    end
         | 
    
        data/lib/commonmarker/node.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require  | 
| 3 | 
            +
            require "commonmarker/node/inspect"
         | 
| 4 4 |  | 
| 5 5 | 
             
            module CommonMarker
         | 
| 6 6 | 
             
              class Node
         | 
| @@ -27,7 +27,7 @@ module CommonMarker | |
| 27 27 | 
             
                # Returns a {String}.
         | 
| 28 28 | 
             
                def to_html(options = :DEFAULT, extensions = [])
         | 
| 29 29 | 
             
                  opts = Config.process_options(options, :render)
         | 
| 30 | 
            -
                  _render_html(opts, extensions).force_encoding( | 
| 30 | 
            +
                  _render_html(opts, extensions).force_encoding("utf-8")
         | 
| 31 31 | 
             
                end
         | 
| 32 32 |  | 
| 33 33 | 
             
                # Public: Convert the node to an XML string.
         | 
| @@ -37,7 +37,7 @@ module CommonMarker | |
| 37 37 | 
             
                # Returns a {String}.
         | 
| 38 38 | 
             
                def to_xml(options = :DEFAULT)
         | 
| 39 39 | 
             
                  opts = Config.process_options(options, :render)
         | 
| 40 | 
            -
                  _render_xml(opts).force_encoding( | 
| 40 | 
            +
                  _render_xml(opts).force_encoding("utf-8")
         | 
| 41 41 | 
             
                end
         | 
| 42 42 |  | 
| 43 43 | 
             
                # Public: Convert the node to a CommonMark string.
         | 
| @@ -48,7 +48,7 @@ module CommonMarker | |
| 48 48 | 
             
                # Returns a {String}.
         | 
| 49 49 | 
             
                def to_commonmark(options = :DEFAULT, width = 120)
         | 
| 50 50 | 
             
                  opts = Config.process_options(options, :render)
         | 
| 51 | 
            -
                  _render_commonmark(opts, width).force_encoding( | 
| 51 | 
            +
                  _render_commonmark(opts, width).force_encoding("utf-8")
         | 
| 52 52 | 
             
                end
         | 
| 53 53 |  | 
| 54 54 | 
             
                # Public: Convert the node to a plain text string.
         | 
| @@ -59,7 +59,7 @@ module CommonMarker | |
| 59 59 | 
             
                # Returns a {String}.
         | 
| 60 60 | 
             
                def to_plaintext(options = :DEFAULT, width = 120)
         | 
| 61 61 | 
             
                  opts = Config.process_options(options, :render)
         | 
| 62 | 
            -
                  _render_plaintext(opts, width).force_encoding( | 
| 62 | 
            +
                  _render_plaintext(opts, width).force_encoding("utf-8")
         | 
| 63 63 | 
             
                end
         | 
| 64 64 |  | 
| 65 65 | 
             
                # Public: Iterate over the children (if any) of the current pointer.
         | 
| @@ -76,7 +76,7 @@ module CommonMarker | |
| 76 76 |  | 
| 77 77 | 
             
                # Deprecated: Please use `each` instead
         | 
| 78 78 | 
             
                def each_child(&block)
         | 
| 79 | 
            -
                  warn | 
| 79 | 
            +
                  warn("[DEPRECATION] `each_child` is deprecated.  Please use `each` instead.")
         | 
| 80 80 | 
             
                  each(&block)
         | 
| 81 81 | 
             
                end
         | 
| 82 82 | 
             
              end
         | 
| @@ -9,8 +9,8 @@ module CommonMarker | |
| 9 9 |  | 
| 10 10 | 
             
                def header(node)
         | 
| 11 11 | 
             
                  block do
         | 
| 12 | 
            -
                    out( | 
| 13 | 
            -
             | 
| 12 | 
            +
                    out("<h", node.header_level, "#{sourcepos(node)}>", :children,
         | 
| 13 | 
            +
                      "</h", node.header_level, ">")
         | 
| 14 14 | 
             
                  end
         | 
| 15 15 | 
             
                end
         | 
| 16 16 |  | 
| @@ -19,10 +19,10 @@ module CommonMarker | |
| 19 19 | 
             
                    out(:children)
         | 
| 20 20 | 
             
                  else
         | 
| 21 21 | 
             
                    block do
         | 
| 22 | 
            -
                      container("<p#{sourcepos(node)}>",  | 
| 22 | 
            +
                      container("<p#{sourcepos(node)}>", "</p>") do
         | 
| 23 23 | 
             
                        out(:children)
         | 
| 24 24 | 
             
                        if node.parent.type == :footnote_definition && node.next.nil?
         | 
| 25 | 
            -
                          out( | 
| 25 | 
            +
                          out(" ")
         | 
| 26 26 | 
             
                          out_footnote_backref
         | 
| 27 27 | 
             
                        end
         | 
| 28 28 | 
             
                      end
         | 
| @@ -36,16 +36,16 @@ module CommonMarker | |
| 36 36 |  | 
| 37 37 | 
             
                  block do
         | 
| 38 38 | 
             
                    if node.list_type == :bullet_list
         | 
| 39 | 
            -
                      container("<ul#{sourcepos(node)}>\n",  | 
| 39 | 
            +
                      container("<ul#{sourcepos(node)}>\n", "</ul>") do
         | 
| 40 40 | 
             
                        out(:children)
         | 
| 41 41 | 
             
                      end
         | 
| 42 42 | 
             
                    else
         | 
| 43 43 | 
             
                      start = if node.list_start == 1
         | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
                      container(start,  | 
| 44 | 
            +
                        "<ol#{sourcepos(node)}>\n"
         | 
| 45 | 
            +
                      else
         | 
| 46 | 
            +
                        "<ol start=\"#{node.list_start}\"#{sourcepos(node)}>\n"
         | 
| 47 | 
            +
                      end
         | 
| 48 | 
            +
                      container(start, "</ol>") do
         | 
| 49 49 | 
             
                        out(:children)
         | 
| 50 50 | 
             
                      end
         | 
| 51 51 | 
             
                    end
         | 
| @@ -57,26 +57,26 @@ module CommonMarker | |
| 57 57 | 
             
                def list_item(node)
         | 
| 58 58 | 
             
                  block do
         | 
| 59 59 | 
             
                    tasklist_data = tasklist(node)
         | 
| 60 | 
            -
                    container("<li#{sourcepos(node)}#{tasklist_data}>#{ | 
| 60 | 
            +
                    container("<li#{sourcepos(node)}#{tasklist_data}>#{" " if tasklist?(node)}", "</li>") do
         | 
| 61 61 | 
             
                      out(:children)
         | 
| 62 62 | 
             
                    end
         | 
| 63 63 | 
             
                  end
         | 
| 64 64 | 
             
                end
         | 
| 65 65 |  | 
| 66 66 | 
             
                def tasklist(node)
         | 
| 67 | 
            -
                  return  | 
| 67 | 
            +
                  return "" unless tasklist?(node)
         | 
| 68 68 |  | 
| 69 69 | 
             
                  state = if checked?(node)
         | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 70 | 
            +
                    'checked="" disabled=""'
         | 
| 71 | 
            +
                  else
         | 
| 72 | 
            +
                    'disabled=""'
         | 
| 73 | 
            +
                  end
         | 
| 74 74 | 
             
                  "><input type=\"checkbox\" #{state} /"
         | 
| 75 75 | 
             
                end
         | 
| 76 76 |  | 
| 77 77 | 
             
                def blockquote(node)
         | 
| 78 78 | 
             
                  block do
         | 
| 79 | 
            -
                    container("<blockquote#{sourcepos(node)}>\n",  | 
| 79 | 
            +
                    container("<blockquote#{sourcepos(node)}>\n", "</blockquote>") do
         | 
| 80 80 | 
             
                      out(:children)
         | 
| 81 81 | 
             
                    end
         | 
| 82 82 | 
             
                  end
         | 
| @@ -93,17 +93,17 @@ module CommonMarker | |
| 93 93 | 
             
                    if option_enabled?(:GITHUB_PRE_LANG)
         | 
| 94 94 | 
             
                      out("<pre#{sourcepos(node)}")
         | 
| 95 95 | 
             
                      out(' lang="', node.fence_info.split(/\s+/)[0], '"') if node.fence_info && !node.fence_info.empty?
         | 
| 96 | 
            -
                      out( | 
| 96 | 
            +
                      out("><code>")
         | 
| 97 97 | 
             
                    else
         | 
| 98 98 | 
             
                      out("<pre#{sourcepos(node)}><code")
         | 
| 99 99 | 
             
                      if node.fence_info && !node.fence_info.empty?
         | 
| 100 100 | 
             
                        out(' class="language-', node.fence_info.split(/\s+/)[0], '">')
         | 
| 101 101 | 
             
                      else
         | 
| 102 | 
            -
                        out( | 
| 102 | 
            +
                        out(">")
         | 
| 103 103 | 
             
                      end
         | 
| 104 104 | 
             
                    end
         | 
| 105 105 | 
             
                    out(escape_html(node.string_content))
         | 
| 106 | 
            -
                    out( | 
| 106 | 
            +
                    out("</code></pre>")
         | 
| 107 107 | 
             
                  end
         | 
| 108 108 | 
             
                end
         | 
| 109 109 |  | 
| @@ -112,7 +112,7 @@ module CommonMarker | |
| 112 112 | 
             
                    if option_enabled?(:UNSAFE)
         | 
| 113 113 | 
             
                      out(tagfilter(node.string_content))
         | 
| 114 114 | 
             
                    else
         | 
| 115 | 
            -
                      out( | 
| 115 | 
            +
                      out("<!-- raw HTML omitted -->")
         | 
| 116 116 | 
             
                    end
         | 
| 117 117 | 
             
                  end
         | 
| 118 118 | 
             
                end
         | 
| @@ -121,22 +121,22 @@ module CommonMarker | |
| 121 121 | 
             
                  if option_enabled?(:UNSAFE)
         | 
| 122 122 | 
             
                    out(tagfilter(node.string_content))
         | 
| 123 123 | 
             
                  else
         | 
| 124 | 
            -
                    out( | 
| 124 | 
            +
                    out("<!-- raw HTML omitted -->")
         | 
| 125 125 | 
             
                  end
         | 
| 126 126 | 
             
                end
         | 
| 127 127 |  | 
| 128 128 | 
             
                def emph(_)
         | 
| 129 | 
            -
                  out( | 
| 129 | 
            +
                  out("<em>", :children, "</em>")
         | 
| 130 130 | 
             
                end
         | 
| 131 131 |  | 
| 132 132 | 
             
                def strong(_)
         | 
| 133 | 
            -
                  out( | 
| 133 | 
            +
                  out("<strong>", :children, "</strong>")
         | 
| 134 134 | 
             
                end
         | 
| 135 135 |  | 
| 136 136 | 
             
                def link(node)
         | 
| 137 | 
            -
                  out('<a href="', node.url.nil? ?  | 
| 137 | 
            +
                  out('<a href="', node.url.nil? ? "" : escape_href(node.url), '"')
         | 
| 138 138 | 
             
                  out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
         | 
| 139 | 
            -
                  out( | 
| 139 | 
            +
                  out(">", :children, "</a>")
         | 
| 140 140 | 
             
                end
         | 
| 141 141 |  | 
| 142 142 | 
             
                def image(node)
         | 
| @@ -145,7 +145,7 @@ module CommonMarker | |
| 145 145 | 
             
                    out(' alt="', :children, '"')
         | 
| 146 146 | 
             
                  end
         | 
| 147 147 | 
             
                  out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
         | 
| 148 | 
            -
                  out( | 
| 148 | 
            +
                  out(" />")
         | 
| 149 149 | 
             
                end
         | 
| 150 150 |  | 
| 151 151 | 
             
                def text(node)
         | 
| @@ -153,9 +153,9 @@ module CommonMarker | |
| 153 153 | 
             
                end
         | 
| 154 154 |  | 
| 155 155 | 
             
                def code(node)
         | 
| 156 | 
            -
                  out( | 
| 156 | 
            +
                  out("<code>")
         | 
| 157 157 | 
             
                  out(escape_html(node.string_content))
         | 
| 158 | 
            -
                  out( | 
| 158 | 
            +
                  out("</code>")
         | 
| 159 159 | 
             
                end
         | 
| 160 160 |  | 
| 161 161 | 
             
                def linebreak(_node)
         | 
| @@ -166,7 +166,7 @@ module CommonMarker | |
| 166 166 | 
             
                  if option_enabled?(:HARDBREAKS)
         | 
| 167 167 | 
             
                    out("<br />\n")
         | 
| 168 168 | 
             
                  elsif option_enabled?(:NOBREAKS)
         | 
| 169 | 
            -
                    out( | 
| 169 | 
            +
                    out(" ")
         | 
| 170 170 | 
             
                  else
         | 
| 171 171 | 
             
                    out("\n")
         | 
| 172 172 | 
             
                  end
         | 
| @@ -199,17 +199,17 @@ module CommonMarker | |
| 199 199 |  | 
| 200 200 | 
             
                def table_cell(node)
         | 
| 201 201 | 
             
                  align = case @alignments[@column_index]
         | 
| 202 | 
            -
             | 
| 203 | 
            -
             | 
| 204 | 
            -
             | 
| 205 | 
            -
             | 
| 206 | 
            -
             | 
| 202 | 
            +
                  when :left then ' align="left"'
         | 
| 203 | 
            +
                  when :right then ' align="right"'
         | 
| 204 | 
            +
                  when :center then ' align="center"'
         | 
| 205 | 
            +
                  else; ""
         | 
| 206 | 
            +
                  end
         | 
| 207 207 | 
             
                  out(@in_header ? "<th#{align}#{sourcepos(node)}>" : "<td#{align}#{sourcepos(node)}>", :children, @in_header ? "</th>\n" : "</td>\n")
         | 
| 208 208 | 
             
                  @column_index += 1
         | 
| 209 209 | 
             
                end
         | 
| 210 210 |  | 
| 211 211 | 
             
                def strikethrough(_)
         | 
| 212 | 
            -
                  out( | 
| 212 | 
            +
                  out("<del>", :children, "</del>")
         | 
| 213 213 | 
             
                end
         | 
| 214 214 |  | 
| 215 215 | 
             
                def footnote_reference(node)
         | 
| @@ -242,7 +242,7 @@ module CommonMarker | |
| 242 242 | 
             
                end
         | 
| 243 243 |  | 
| 244 244 | 
             
                def tasklist?(node)
         | 
| 245 | 
            -
                  node.type_string ==  | 
| 245 | 
            +
                  node.type_string == "tasklist"
         | 
| 246 246 | 
             
                end
         | 
| 247 247 |  | 
| 248 248 | 
             
                def checked?(node)
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require  | 
| 4 | 
            -
            require  | 
| 3 | 
            +
            require "set"
         | 
| 4 | 
            +
            require "stringio"
         | 
| 5 5 |  | 
| 6 6 | 
             
            module CommonMarker
         | 
| 7 7 | 
             
              class Renderer
         | 
| @@ -9,9 +9,9 @@ module CommonMarker | |
| 9 9 |  | 
| 10 10 | 
             
                def initialize(options: :DEFAULT, extensions: [])
         | 
| 11 11 | 
             
                  @opts = Config.process_options(options, :render)
         | 
| 12 | 
            -
                  @stream = StringIO.new(+ | 
| 12 | 
            +
                  @stream = StringIO.new(+"")
         | 
| 13 13 | 
             
                  @need_blocksep = false
         | 
| 14 | 
            -
                  @warnings = Set.new | 
| 14 | 
            +
                  @warnings = Set.new([])
         | 
| 15 15 | 
             
                  @in_tight = false
         | 
| 16 16 | 
             
                  @in_plain = false
         | 
| 17 17 | 
             
                  @tagfilter = extensions.include?(:tagfilter)
         | 
| @@ -121,7 +121,7 @@ module CommonMarker | |
| 121 121 | 
             
                end
         | 
| 122 122 |  | 
| 123 123 | 
             
                def sourcepos(node)
         | 
| 124 | 
            -
                  return  | 
| 124 | 
            +
                  return "" unless option_enabled?(:SOURCEPOS)
         | 
| 125 125 |  | 
| 126 126 | 
             
                  s = node.sourcepos
         | 
| 127 127 | 
             
                  " data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
         | 
    
        data/lib/commonmarker/version.rb
    CHANGED
    
    
    
        data/lib/commonmarker.rb
    CHANGED
    
    | @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 | 
            -
            require  | 
| 5 | 
            -
            require  | 
| 6 | 
            -
            require  | 
| 7 | 
            -
            require  | 
| 8 | 
            -
            require  | 
| 9 | 
            -
            require  | 
| 4 | 
            +
            require "commonmarker/commonmarker"
         | 
| 5 | 
            +
            require "commonmarker/config"
         | 
| 6 | 
            +
            require "commonmarker/node"
         | 
| 7 | 
            +
            require "commonmarker/renderer"
         | 
| 8 | 
            +
            require "commonmarker/renderer/html_renderer"
         | 
| 9 | 
            +
            require "commonmarker/version"
         | 
| 10 10 |  | 
| 11 11 | 
             
            begin
         | 
| 12 | 
            -
              require  | 
| 12 | 
            +
              require "awesome_print"
         | 
| 13 13 | 
             
            rescue LoadError; end # rubocop:disable Lint/SuppressedException
         | 
| 14 14 | 
             
            module CommonMarker
         | 
| 15 15 | 
             
              # Public:  Parses a Markdown string into an HTML string.
         | 
| @@ -23,9 +23,7 @@ module CommonMarker | |
| 23 23 | 
             
                raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
         | 
| 24 24 |  | 
| 25 25 | 
             
                opts = Config.process_options(options, :render)
         | 
| 26 | 
            -
                text | 
| 27 | 
            -
                html = Node.markdown_to_html(text, opts, extensions)
         | 
| 28 | 
            -
                html.force_encoding('UTF-8')
         | 
| 26 | 
            +
                Node.markdown_to_html(text.encode("UTF-8"), opts, extensions)
         | 
| 29 27 | 
             
              end
         | 
| 30 28 |  | 
| 31 29 | 
             
              # Public: Parses a Markdown string into a `document` node.
         | 
| @@ -39,7 +37,7 @@ module CommonMarker | |
| 39 37 | 
             
                raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
         | 
| 40 38 |  | 
| 41 39 | 
             
                opts = Config.process_options(options, :parse)
         | 
| 42 | 
            -
                text = text.encode( | 
| 40 | 
            +
                text = text.encode("UTF-8")
         | 
| 43 41 | 
             
                Node.parse_document(text, text.bytesize, opts, extensions)
         | 
| 44 42 | 
             
              end
         | 
| 45 43 | 
             
            end
         |