Skip to content

Commit 883c0ce

Browse files
committed
v3.2.4
1 parent 472572b commit 883c0ce

23 files changed

+512
-212
lines changed

.eslintrc.yml

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ root: true
1818

1919
env:
2020
node: true
21-
#es6: true
22-
23-
ecmaFeatures:
24-
modules: true
21+
es6: true
2522

2623
parserOptions:
27-
sourceType: "module"
24+
sourceType: "module"
25+
ecmaVersion: 6
26+
ecmaFeatures:
27+
impliedStrict: true
2828

2929
###########################################################################
3030
# GLOBALS #
@@ -142,7 +142,7 @@ rules:
142142
new-parens: 2 # disallow the omission of parentheses when invoking a constructor with no arguments (Default: 0)
143143
no-array-constructor: 2 # disallow use of the Array constructor (Default: 0)
144144
no-lonely-if: 2 # disallow if as the only statement in an else block
145-
no-multiple-empty-lines: [2, {"max": 1}]
145+
no-multiple-empty-lines: [2, {"max": 2}]
146146
# disallow multiple empty lines
147147
no-new-object: 2 # disallow use of the Object constructor (Default: 0)
148148
no-restricted-syntax: [2, "WithStatement"] # disallow use of `with` statements in code

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Compiler Changes
22

3+
### v3.2.4
4+
- Fix [riot#2369](https://github.com/riot/riot/issues/2369) : Possible bug involving compilation of tags containing regex.
5+
- Using the `skip-regex` function from npm for sharing bwteen modules (at future).
6+
- Using the `jsSplitter` function for safer replacement of JS code, part of the next compiler.
7+
38
### v3.2.3
49
- Fixes various issues with literal regexes.
510

Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ LIB = "./lib/"
2222
# default job
2323
test: build test-mocha
2424

25-
build: clean eslint pre-build
25+
build: clean pre-build eslint
2626
# build riot and es6 versions
2727
@ mkdir -p $(DIST)
2828
@ $(JSPP) $(JSPP_RIOT_FLAGS) src/_riot.js > $(DIST)riot.compiler.js
@@ -35,6 +35,7 @@ pre-build:
3535
# build the node version
3636
@ $(JSPP) $(JSPP_NODE_FLAGS) src/core.js > $(LIB)compiler.js
3737
@ $(JSPP) $(JSPP_NODE_FLAGS) src/safe-regex.js > $(LIB)safe-regex.js
38+
@ $(JSPP) $(JSPP_NODE_FLAGS) src/js-splitter.js > $(LIB)js-splitter.js
3839

3940
eslint:
4041
# check code style

lib/brackets.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
var safeRegex = require('./safe-regex')
9-
var skipRegex = require('./skip-regex')
9+
var skipRegex = require('skip-regex')
1010

1111
/**
1212
* Matches valid, multiline JavaScript comments in almost all its forms.
@@ -39,7 +39,7 @@ var S_QBLOCKS = R_STRINGS.source + '|' +
3939
/*
4040
JS/ES6 quoted strings and start of regex (basic ES6 does not supports nested backquotes).
4141
*/
42-
var S_QBLOCK2 = R_STRINGS.source + '|' + /(\/)(?![*\/])/.source
42+
var S_QBLOCK2 = R_STRINGS.source + '|(/)(?![*/])'
4343

4444
/**
4545
* Hash of regexes for matching JavaScript brackets out of quoted strings and literal

lib/compiler.js

+22-40
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/**
2-
* The riot-compiler v3.2.3
2+
* The riot-compiler v3.2.4
33
*
44
* @module compiler
5-
* @version v3.2.3
5+
* @version v3.2.4
66
* @license MIT
77
* @copyright Muut Inc. + contributors
88
*/
@@ -11,6 +11,7 @@
1111
var brackets = require('./brackets')
1212
var parsers = require('./parsers')
1313
var safeRegex = require('./safe-regex')
14+
var jsSplitter = require('./js-splitter')
1415
var path = require('path')
1516

1617
var extend = require('./parsers/_utils').mixobj
@@ -339,23 +340,6 @@ function compileHTML (html, opts, pcex) {
339340
*/
340341
var JS_ES6SIGN = /^[ \t]*(((?:async|\*)\s*)?([$_A-Za-z][$\w]*))\s*\([^()]*\)\s*{/m
341342

342-
/**
343-
* Regex for remotion of multiline and single-line JavaScript comments, merged with
344-
* {@link module:brackets.S_QBLOCKS|brackets.S_QBLOCKS} to skip literal string and regexes.
345-
* Used by the {@link module:compiler~riotjs|riotjs} parser.
346-
*
347-
* 2016-01-18: rewritten to not capture the brackets (reduces 9 steps)
348-
* @const {RegExp}
349-
*/
350-
var JS_ES6END = RegExp('[{}]|' + brackets.S_QBLOCKS, 'g')
351-
352-
/**
353-
* Regex for remotion of multiline and single-line JavaScript comments, merged with
354-
* {@link module:brackets.S_QBLOCKS|brackets.S_QBLOCKS} to skip literal string and regexes.
355-
* @const {RegExp}
356-
*/
357-
var JS_COMMS = RegExp(brackets.R_MLCOMMS.source + '|//[^\r\n]*|' + brackets.S_QBLOCK2, 'g')
358-
359343
/**
360344
* Default parser for JavaScript, supports ES6-like method syntax
361345
*
@@ -373,13 +357,14 @@ function riotjs (js) {
373357
name,
374358
RE = RegExp
375359

376-
if (~js.indexOf('/')) js = rmComms(js, JS_COMMS)
360+
const src = jsSplitter(js)
361+
js = src.shift().join('<%>')
377362

378363
while ((match = js.match(JS_ES6SIGN))) {
379364

380365
parts.push(RE.leftContext)
381366
js = RE.rightContext
382-
pos = skipBody(js, JS_ES6END)
367+
pos = skipBody(js)
383368

384369
method = match[1]
385370
prefix = match[2] || ''
@@ -399,28 +384,25 @@ function riotjs (js) {
399384
if (toes5 && !/^\s*.\s*bind\b/.test(js)) parts.push('.bind(this)')
400385
}
401386

402-
return parts.length ? parts.join('') + js : js
387+
if (parts.length) {
388+
js = parts.join('') + js
389+
}
403390

404-
function rmComms (s, r, m) {
405-
r.lastIndex = 0
406-
while ((m = r.exec(s))) {
407-
if (m[1]) {
408-
r.lastIndex = brackets.skipRegex(s, m.index)
409-
} else if (m[0][0] === '/') {
410-
s = s.slice(0, m.index) + ' ' + s.slice(r.lastIndex)
411-
r.lastIndex = m.index + 1
412-
}
413-
}
414-
return s
391+
if (src.length) {
392+
js = js.replace(/<%>/g, function () {
393+
return src.shift()
394+
})
415395
}
416396

417-
function skipBody (s, r) {
418-
var m, i = 1
397+
return js
398+
399+
function skipBody (s) {
400+
var r = /[{}]/g
401+
var i = 1
419402

420-
r.lastIndex = 0
421-
while (i && (m = r.exec(s))) {
422-
if (m[0] === '{') ++i
423-
else if (m[0] === '}') --i
403+
while (i && r.exec(s)) {
404+
if (s[r.lastIndex - 1] === '{') ++i
405+
else --i
424406
}
425407
return i ? s.length : r.lastIndex
426408
}
@@ -1010,5 +992,5 @@ module.exports = {
1010992
css: compileCSS,
1011993
js: compileJS,
1012994
parsers: parsers,
1013-
version: 'v3.2.3'
995+
version: 'v3.2.4'
1014996
}

lib/js-splitter.js

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
2+
var skipRegex = require('skip-regex')
3+
4+
var S_SQ_STR = /'[^'\n\r\\]*(?:\\(?:\r\n?|[\S\s])[^'\n\r\\]*)*'/.source
5+
6+
var S_R_SRC1 = [
7+
/\/\*[^*]*\*+(?:[^*\/][^*]*\*+)*\//.source,
8+
'//.*',
9+
S_SQ_STR,
10+
S_SQ_STR.replace(/'/g, '"'),
11+
'([/`])'
12+
].join('|')
13+
14+
var S_R_SRC2 = `${S_R_SRC1.slice(0, -2)}{}])`
15+
16+
/**
17+
* Simple ES6 Template Literal parser, it searches the next back-quote that
18+
* signals the end of the ES6TL or the `${` sequence that starts a JS expression,
19+
* skipping any escaped character.
20+
*
21+
* @param {string} code - Whole code
22+
* @param {number} start - The start position of the template
23+
* @param {number} stack - To save nested ES6 TL count
24+
* @returns {number} The end of the string (-1 if not found)
25+
*/
26+
function skipES6str (code, start, stack) {
27+
28+
var re = /[`$\\]/g
29+
30+
re.lastIndex = start
31+
while (re.exec(code)) {
32+
var end = re.lastIndex
33+
var c = code[end - 1]
34+
35+
if (c === '`') {
36+
return end
37+
}
38+
if (c === '$' && code[end] === '{') {
39+
stack.push('`', '}')
40+
return end + 1
41+
}
42+
re.lastIndex++
43+
}
44+
45+
throw new Error('Unclosed ES6 template')
46+
}
47+
48+
/**
49+
* Parses the code string searching the end of the expression.
50+
* @param {string} code - Buffer to parse
51+
* @param {number} [start=0] - Start position of the parsing
52+
* @returns {Array} Expression's end (after the closing brace) or -1 if it is not an expr.
53+
* @class
54+
*/
55+
function jsSplitter (code, start) {
56+
57+
var re1 = new RegExp(S_R_SRC1, 'g')
58+
var re2
59+
60+
var offset = start |= 0
61+
var result = [[]]
62+
var stack = []
63+
var re = re1
64+
65+
var lastPos = re.lastIndex = offset
66+
var str, ch, idx, end, match
67+
68+
while ((match = re.exec(code))) {
69+
idx = match.index
70+
end = re.lastIndex
71+
str = ''
72+
ch = match[1]
73+
74+
if (ch) {
75+
76+
if (ch === '{') {
77+
stack.push('}')
78+
79+
} else if (ch === '}') {
80+
if (stack.pop() !== ch) {
81+
throw new Error("Unexpected '}'")
82+
83+
} else if (stack[stack.length - 1] === '`') {
84+
ch = stack.pop()
85+
}
86+
87+
} else if (ch === '/') {
88+
end = skipRegex(code, idx)
89+
90+
if (end > idx + 1) {
91+
str = code.slice(idx, end)
92+
}
93+
}
94+
95+
if (ch === '`') {
96+
end = skipES6str(code, end, stack)
97+
str = code.slice(idx, end)
98+
99+
if (stack.length) {
100+
re = re2 || (re2 = new RegExp(S_R_SRC2, 'g'))
101+
} else {
102+
re = re1
103+
}
104+
}
105+
106+
} else {
107+
108+
str = match[0]
109+
110+
if (str[0] === '/') {
111+
str = str[1] === '*' ? ' ' : ''
112+
code = code.slice(offset, idx) + str + code.slice(end)
113+
end = idx + str.length
114+
str = ''
115+
116+
} else if (str.length === 2) {
117+
str = ''
118+
}
119+
}
120+
121+
if (str) {
122+
result[0].push(code.slice(lastPos, idx))
123+
result.push(str)
124+
lastPos = end
125+
}
126+
127+
re.lastIndex = end
128+
}
129+
130+
result[0].push(code.slice(lastPos))
131+
132+
return result
133+
}
134+
135+
module.exports = jsSplitter

0 commit comments

Comments
 (0)