Skip to content

Commit

Permalink
JavaScript: Support dotted names as keywords
Browse files Browse the repository at this point in the history
  • Loading branch information
akx committed Feb 7, 2016
1 parent 8fee76c commit d0c3853
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 5 deletions.
7 changes: 6 additions & 1 deletion babel/messages/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,13 @@ def extract_javascript(fileobj, keywords, comment_tags, options):
encoding = options.get('encoding', 'utf-8')
last_token = None
call_stack = -1
dotted = any('.' in kw for kw in keywords)

for token in tokenize(fileobj.read().decode(encoding), jsx=options.get("jsx", True)):
for token in tokenize(
fileobj.read().decode(encoding),
jsx=options.get("jsx", True),
dotted=dotted
):
if token.type == 'operator' and token.value == '(':
if funcname:
message_lineno = token.lineno
Expand Down
15 changes: 11 additions & 4 deletions babel/messages/jslexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@

escapes = {'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t'}

name_re = re.compile(r'[\w$_][\w\d$_]*', re.UNICODE)
dotted_name_re = re.compile(r'[\w$_][\w\d$_.]*[\w\d$_.]', re.UNICODE)
division_re = re.compile(r'/=?')
regex_re = re.compile(r'/(?:[^/\\]*(?:\\.[^/\\]*)*)/[a-zA-Z]*(?s)')
line_re = re.compile(r'(\r\n|\n|\r)')
line_join_re = re.compile(r'\\' + line_re.pattern)
uni_escape_re = re.compile(r'[a-fA-F0-9]{1,4}')
name_re = re.compile(r'(\$+\w*|[^\W\d]\w*)(?u)')

Token = namedtuple('Token', 'type value lineno')

Expand All @@ -36,6 +37,7 @@
(None, re.compile(r'<!--.*')),
('linecomment', re.compile(r'//.*')),
('multilinecomment', re.compile(r'/\*.*?\*/(?us)')),
('dotted_name', dotted_name_re),
('name', name_re),
('number', re.compile(r'''(?x)(
(?:0|[1-9]\d*)
Expand All @@ -52,7 +54,7 @@
]


def get_rules(jsx):
def get_rules(jsx, dotted):
"""
Get a tokenization rule list given the passed syntax options.
Expand All @@ -62,6 +64,10 @@ def get_rules(jsx):
for token_type, rule in _rules:
if not jsx and token_type and 'jsx' in token_type:
continue
if token_type == 'dotted_name':
if not dotted:
continue
token_type = 'name'
rules.append((token_type, rule))
return rules

Expand Down Expand Up @@ -131,17 +137,18 @@ def unquote_string(string):
return u''.join(result)


def tokenize(source, jsx=True):
def tokenize(source, jsx=True, dotted=True):
"""
Tokenize JavaScript/JSX source. Returns a generator of tokens.
:param jsx: Enable (limited) JSX parsing.
:param dotted: Read dotted names as single name token.
"""
may_divide = False
pos = 0
lineno = 1
end = len(source)
rules = get_rules(jsx=jsx)
rules = get_rules(jsx=jsx, dotted=dotted)

while pos < end:
# handle regular rules first
Expand Down
9 changes: 9 additions & 0 deletions tests/messages/test_js_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,12 @@ def test_jsx_extraction(jsx_enabled):
assert messages == EXPECTED_JSX_MESSAGES
else:
assert messages != EXPECTED_JSX_MESSAGES


def test_dotted_keyword_extract():
buf = BytesIO(b"msg1 = com.corporate.i18n.formatMessage('Insert coin to continue')")
messages = list(
extract.extract('javascript', buf, {"com.corporate.i18n.formatMessage": None}, [], {})
)

assert messages == [(1, 'Insert coin to continue', [], None)]
19 changes: 19 additions & 0 deletions tests/messages/test_jslexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,22 @@
def test_unquote():
assert jslexer.unquote_string('""') == ''
assert jslexer.unquote_string(r'"h\u00ebllo"') == u"hëllo"


def test_dollar_in_identifier():
assert list(jslexer.tokenize('dollar$dollar')) == [('name', 'dollar$dollar', 1)]


def test_dotted_name():
assert list(jslexer.tokenize("foo.bar(quux)", dotted=True)) == [
('name', 'foo.bar', 1),
('operator', '(', 1),
('name', 'quux', 1),
('operator', ')', 1)
]


def test_dotted_name_end():
assert list(jslexer.tokenize("foo.bar", dotted=True)) == [
('name', 'foo.bar', 1),
]

0 comments on commit d0c3853

Please sign in to comment.