Skip to content
This repository was archived by the owner on Mar 26, 2022. It is now read-only.

Commit 1b68ed8

Browse files
authored
Merge pull request #143 from iamahuman/fix029
Synchronize code with upstream commonmark.js 0.29
2 parents 75add17 + cee6b84 commit 1b68ed8

File tree

9 files changed

+700
-235
lines changed

9 files changed

+700
-235
lines changed

commonmark/blocks.py

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
from __future__ import absolute_import, unicode_literals
22

33
import re
4-
from importlib import import_module
54
from commonmark import common
65
from commonmark.common import unescape_string
76
from commonmark.inlines import InlineParser
87
from commonmark.node import Node
9-
from commonmark.utils import to_camel_case
108

119

1210
CODE_INDENT = 4
@@ -21,7 +19,7 @@
2119
r'^<[/]?(?:address|article|aside|base|basefont|blockquote|body|'
2220
r'caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|'
2321
r'fieldset|figcaption|figure|footer|form|frame|frameset|h1|head|'
24-
r'header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|'
22+
r'header|hr|html|iframe|legend|li|link|main|menu|menuitem|'
2523
r'nav|noframes|ol|optgroup|option|p|param|section|source|title|'
2624
r'summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)'
2725
r'(?:\s|[/]?[>]|$)',
@@ -45,7 +43,7 @@
4543
reBulletListMarker = re.compile(r'^[*+-]')
4644
reOrderedListMarker = re.compile(r'^(\d{1,9})([.)])')
4745
reATXHeadingMarker = re.compile(r'^#{1,6}(?:[ \t]+|$)')
48-
reCodeFence = re.compile(r'^`{3,}(?!.*`)|^~{3,}(?!.*~)')
46+
reCodeFence = re.compile(r'^`{3,}(?!.*`)|^~{3,}')
4947
reClosingCodeFence = re.compile(r'^(?:`{3,}|~{3,})(?= *$)')
5048
reSetextHeadingLine = re.compile(r'^(?:=+|-+)[ \t]*$')
5149
reLineEnding = re.compile(r'\r\n|\n|\r')
@@ -57,7 +55,7 @@ def is_blank(s):
5755

5856

5957
def is_space_or_tab(s):
60-
return s == ' ' or s == '\t'
58+
return s in (' ', '\t')
6159

6260

6361
def peek(ln, pos):
@@ -73,9 +71,12 @@ def ends_with_blank_line(block):
7371
while block:
7472
if block.last_line_blank:
7573
return True
76-
if (block.t == 'list' or block.t == 'item'):
74+
if not block.last_line_checked and \
75+
block.t in ('list', 'item'):
76+
block.last_line_checked = True
7777
block = block.last_child
7878
else:
79+
block.last_line_checked = True
7980
break
8081

8182
return False
@@ -94,6 +95,8 @@ def parse_list_marker(parser, container):
9495
'padding': None,
9596
'marker_offset': parser.indent,
9697
}
98+
if parser.indent >= 4:
99+
return None
97100
m = re.search(reBulletListMarker, rest)
98101
m2 = re.search(reOrderedListMarker, rest)
99102
if m:
@@ -515,15 +518,25 @@ def setext_heading(parser, container=None):
515518
parser.current_line[parser.next_nonspace:])
516519
if m:
517520
parser.close_unmatched_blocks()
518-
heading = Node('heading', container.sourcepos)
519-
heading.level = 1 if m.group()[0] == '=' else 2
520-
heading.string_content = container.string_content
521-
container.insert_after(heading)
522-
container.unlink()
523-
parser.tip = heading
524-
parser.advance_offset(
525-
len(parser.current_line) - parser.offset, False)
526-
return 2
521+
# resolve reference link definitiosn
522+
while peek(container.string_content, 0) == '[':
523+
pos = parser.inline_parser.parseReference(
524+
container.string_content, parser.refmap)
525+
if not pos:
526+
break
527+
container.string_content = container.string_content[pos:]
528+
if container.string_content:
529+
heading = Node('heading', container.sourcepos)
530+
heading.level = 1 if m.group()[0] == '=' else 2
531+
heading.string_content = container.string_content
532+
container.insert_after(heading)
533+
container.unlink()
534+
parser.tip = heading
535+
parser.advance_offset(
536+
len(parser.current_line) - parser.offset, False)
537+
return 2
538+
else:
539+
return 0
527540

528541
return 0
529542

@@ -610,13 +623,8 @@ def add_child(self, tag, offset):
610623
""" Add block of type tag as a child of the tip. If the tip can't
611624
accept children, close and finalize it and try its parent,
612625
and so on til we find a block that can accept children."""
613-
block_class = getattr(import_module('commonmark.blocks'),
614-
to_camel_case(self.tip.t))
615-
while not block_class.can_contain(tag):
626+
while not self.blocks[self.tip.t].can_contain(tag):
616627
self.finalize(self.tip, self.line_number - 1)
617-
block_class = getattr(
618-
import_module('commonmark.blocks'),
619-
to_camel_case(self.tip.t))
620628

621629
column_number = offset + 1
622630
new_block = Node(tag, [[self.line_number, column_number], [0, 0]])
@@ -725,15 +733,15 @@ def incorporate_line(self, ln):
725733
# For each containing block, try to parse the associated line start.
726734
# Bail out on failure: container will point to the last matching block.
727735
# Set all_matched to false if not all containers match.
728-
last_child = container.last_child
729-
while last_child and last_child.is_open:
736+
while True:
737+
last_child = container.last_child
738+
if not (last_child and last_child.is_open):
739+
break
730740
container = last_child
731741

732742
self.find_next_nonspace()
733-
block_class = getattr(
734-
import_module('commonmark.blocks'),
735-
to_camel_case(container.t))
736-
rv = block_class.continue_(self, container)
743+
744+
rv = self.blocks[container.t].continue_(self, container)
737745
if rv == 0:
738746
# we've matched, keep going
739747
pass
@@ -745,21 +753,19 @@ def incorporate_line(self, ln):
745753
self.last_line_length = len(ln)
746754
return
747755
else:
748-
raise ValueError('returned illegal value, must be 0, 1, or 2')
756+
raise ValueError(
757+
'continue_ returned illegal value, must be 0, 1, or 2')
749758

750759
if not all_matched:
751760
# back up to last matching block
752761
container = container.parent
753762
break
754763

755-
last_child = container.last_child
756-
757764
self.all_closed = (container == self.oldtip)
758765
self.last_matched_container = container
759766

760-
block_class = getattr(import_module('commonmark.blocks'),
761-
to_camel_case(container.t))
762-
matched_leaf = container.t != 'paragraph' and block_class.accepts_lines
767+
matched_leaf = container.t != 'paragraph' and \
768+
self.blocks[container.t].accepts_lines
763769
starts = self.block_starts
764770
starts_len = len(starts.METHODS)
765771
# Unless last matched container is a code block, try new container
@@ -824,9 +830,7 @@ def incorporate_line(self, ln):
824830
cont.last_line_blank = last_line_blank
825831
cont = cont.parent
826832

827-
block_class = getattr(import_module('commonmark.blocks'),
828-
to_camel_case(t))
829-
if block_class.accepts_lines:
833+
if self.blocks[t].accepts_lines:
830834
self.add_line()
831835
# if HtmlBlock, check for end condition
832836
if t == 'html_block' and \
@@ -853,9 +857,8 @@ def finalize(self, block, line_number):
853857
above = block.parent
854858
block.is_open = False
855859
block.sourcepos[1] = [line_number, self.last_line_length]
856-
block_class = getattr(import_module('commonmark.blocks'),
857-
to_camel_case(block.t))
858-
block_class.finalize(self, block)
860+
861+
self.blocks[block.t].finalize(self, block)
859862

860863
self.tip = above
861864

@@ -897,3 +900,9 @@ def parse(self, my_input):
897900
self.finalize(self.tip, length)
898901
self.process_inlines(self.doc)
899902
return self.doc
903+
904+
905+
CAMEL_RE = re.compile("(.)([A-Z](?:[a-z]+|(?<=[a-z0-9].)))")
906+
Parser.blocks = dict(
907+
(CAMEL_RE.sub(r'\1_\2', cls.__name__).lower(), cls)
908+
for cls in Block.__subclasses__())

commonmark/common.py

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from commonmark import entitytrans
2020
HTMLunescape = entitytrans._unescape
2121

22-
ENTITY = '&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});'
22+
ENTITY = '&(?:#x[a-f0-9]{1,6}|#[0-9]{1,7}|[a-z][a-z0-9]{1,31});'
2323

2424
TAGNAME = '[A-Za-z][A-Za-z0-9-]*'
2525
ATTRIBUTENAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*'
@@ -45,7 +45,6 @@
4545
'\\\\' + ESCAPABLE + '|' + ENTITY, re.IGNORECASE)
4646
XMLSPECIAL = '[&<>"]'
4747
reXmlSpecial = re.compile(XMLSPECIAL)
48-
reXmlSpecialOrEntity = re.compile(ENTITY + '|' + XMLSPECIAL, re.IGNORECASE)
4948

5049

5150
def unescape_char(s):
@@ -102,19 +101,13 @@ def replace_unsafe_char(s):
102101
return UNSAFE_MAP.get(s, s)
103102

104103

105-
def escape_xml(s, preserve_entities):
104+
def escape_xml(s):
106105
if s is None:
107106
return ''
108107
if re.search(reXmlSpecial, s):
109-
if preserve_entities:
110-
return re.sub(
111-
reXmlSpecialOrEntity,
112-
lambda m: replace_unsafe_char(m.group()),
113-
s)
114-
else:
115-
return re.sub(
116-
reXmlSpecial,
117-
lambda m: replace_unsafe_char(m.group()),
118-
s)
108+
return re.sub(
109+
reXmlSpecial,
110+
lambda m: replace_unsafe_char(m.group()),
111+
s)
119112
else:
120113
return s

0 commit comments

Comments
 (0)