Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.3.13 #12

Merged
merged 13 commits into from
Nov 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ out/
node_modules
bower_components
coverage
cov-int

# these files are generated anyway
dist/
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ build: eslint

bump:
# Bump the version
@ sed -i '' 's/WIP/v$(VERSION)/' $(DIST)*tmpl.js
@ sed -i 's/WIP/v$(VERSION)/' $(DIST)*tmpl.js

eslint:
# check code style
Expand Down
7 changes: 4 additions & 3 deletions dist/riot.tmpl.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@

/**
* The riot template engine
* @version v2.3.1
* @version WIP
*/

/**
* @module brackets
*
* `brackets ` Returns a string or regex based on its parameter
* `brackets.settings` Mirrors the `riot.settings` object
* `brackets.set ` The recommended option to change the current tiot brackets
* `brackets.set ` The recommended form to change the current riot brackets
*/

var brackets = (function (UNDEF) {
Expand Down Expand Up @@ -64,7 +64,8 @@ var brackets = (function (UNDEF) {
_pairs = bp.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' '))
_regex = _rewrite
}
_pairs[4] = _regex(_pairs[1].length > 1 ? /(?:^|[^\\]){[\S\s]*?}/ : /(?:^|[^\\]){[^}]*}/)

_pairs[4] = _regex(_pairs[1].length > 1 ? /{[\S\s]*?}/ : /{[^}]*}/)
_pairs[5] = _regex(/\\({|})/g)
_pairs[6] = _regex(/(\\?)({)/g)
_pairs[7] = _regExp('(\\\\?)(?:([[({])|(' + _pairs[3] + '))|' + S_QBSRC, REGLOB)
Expand Down
7 changes: 4 additions & 3 deletions dist/tmpl.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* riot-tmpl v2.3.1, @license MIT, (c) 2015 Muut Inc. + contributors */
/* riot-tmpl WIP, @license MIT, (c) 2015 Muut Inc. + contributors */
;(function (window) {
'use strict' // eslint-disable-line

Expand All @@ -7,7 +7,7 @@
*
* `brackets ` Returns a string or regex based on its parameter
* `brackets.settings` Mirrors the `riot.settings` object
* `brackets.set ` The recommended option to change the current tiot brackets
* `brackets.set ` The recommended form to change the current riot brackets
*/

var brackets = (function (UNDEF) {
Expand Down Expand Up @@ -62,7 +62,8 @@
_pairs = bp.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' '))
_regex = _rewrite
}
_pairs[4] = _regex(_pairs[1].length > 1 ? /(?:^|[^\\]){[\S\s]*?}/ : /(?:^|[^\\]){[^}]*}/)

_pairs[4] = _regex(_pairs[1].length > 1 ? /{[\S\s]*?}/ : /{[^}]*}/)
_pairs[5] = _regex(/\\({|})/g)
_pairs[6] = _regex(/(\\?)({)/g)
_pairs[7] = _regExp('(\\\\?)(?:([[({])|(' + _pairs[3] + '))|' + S_QBSRC, REGLOB)
Expand Down
131 changes: 86 additions & 45 deletions doc/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,44 +18,23 @@ _parameters_
_returns:_ string - Raw value of the expression or template to render


### `tmpl.hasExpr` function
### `hasExpr` function (alias)

_usage:_ `tmpl.hasExpr( str )`
This is an alias to [`brackets.hasExpr`](#hasxpr-function)

Checks for an expression within a string, using the current brackets.

_parameters_

* `str` : string - String where to search

_returns:_ boolean - `true` if the string contains an expression
### `loopKeys` function (alias, private)

NOTE: This function only checks for a pair of unescaped riot brackets, does not validate
the expression nor excludes brackets within quotes.
This is an alias to [`brackets.loopKeys`](#loopkeys-function-private)


### `tmpl.loopKeys` function

_usage:_ `tmpl.loopKeys( expr )`

Parses the `each` expression to detect how to map the collection data to the child tags
(used by browser/tag/each.js)
If the received string does not contains an expression, the behavior is undefined.

_parameters_

* `expr` : string - value of the 'each' attribute

_returns:_ object - object needed to check how the items in the collection should be mapped to the child tags


### `tmpl.errorHandler` property
### `errorHandler` property

_type:_ function

Defines a custom function to handle evaluation errors.

The `errorHandler` property allows to detect errors _in the evaluation_, by setting its value to a function that receives the generated Error object, augmented with an object `riotData` containing the properties `tagName` and `\_riot_id` of the context at error time.
The `tmpl.errorHandler` property allows to detect errors _in the evaluation_, by setting its value to a function that receives the generated Error object, augmented with an object `riotData` containing the properties `tagName` and `_riot_id` of the context at error time.

Other (usually fatal) errors, such as "Parse Error" generated by the Function constructor, are not intercepted.

Expand All @@ -67,75 +46,137 @@ If this property is not set, or set to falsy, as in previous versions the error
Since v2.3, setting the brackets to some characters throws an exception.
This is the list of invalid characters:

- Control characters from `\x00` to `\x1F` that can be changed by browsers or minifier tools
- Control characters from `\x00` to `\x1F` that can be changed by browsers or minification tools
- Alphanumeric `a-z`, `A-Z`, and `0-9`, wich are confused with JS variable names
- Single and double quotes, comma, semicolon and backslash `'`, `"`, `,`, `;`, `\`, for obvious reasons
- The dangerous `<` and `>` characters, reserved for use in markup and strictly prohibited in unquoted text for any other purpose -- out of CDATA sections.

See the [CHANGES](CHANGES.md) document for details.


### `brackets` function

_Syntax:_ `brackets( RegExp | number ) : RegExp | string`
_Syntax:_ `brackets( reOrIdx ) : RegExp | string`

The brackets function accepts a RegExp or numeric parameter.

With a numeric parameter, brackets returns the current left (0) or right (1) bracket characters.
_parameters_

* `reOrIdx` : RegExp or number - regex to convert or index number of backets part

_returns:_ RegExp or string - With a regex, this function returns the original regex if the current brackets are the defaults, or a new one with the default brackets replaced by the current custom brackets.
With a numeric parameter, returns a value based on current brackets according to the following table (defaults are within parenthesis):

With a regex, this function returns the original regex if the current brackets are the defaults, or a new one with the default brackets replaced by the current custom brackets.
* 0: left bracket (`{`)
* 1: right bracket (`}`)
* 2: left escaped bracket (`{`)*
* 3: right escaped bracket (`}`)*
* 4: RegExp which matches an unescaped barckets pair (`/(?:^\|[^\\]){[^}]*}/`)\*\*

\* only characters `[]()*+?.^$|` are escaped.

### `brackets.set` function
\*\* not 100% accurate, because it does not recognize brackets within strings.

_Syntax:_ `brackets.set( brackets_string )`

Receives the new string for the brackets pair. This function checks their parameter and reconfigures the internal state immediately.
### `set` function

_Syntax:_ `brackets.set( brackets_pair )`

### `brackets.settings` property
Receives the new string for the brackets pair. If you pass a falsy value, brackets are reset to default.
This function checks their parameter and reconfigures the internal state immediately.

_parameters_

* `brackets_pair` : string - new custom brackets pair. The start and end is separated with a space character.


### `settings` property

_Type:_ object

Mirror the `riot.settings` object or other user object with where read or write the current brackets string. Unlike with `brackets.set`, reconfiguration for changes in this property, called `brackets`, will be applied in the next use of the `brackets` function.
Mirror the `riot.settings` object or other user object where read or write the current brackets string. Unlike with `brackets.set`, reconfiguration for changes in `brackets.settings.brackets` or `riot.settings.brackets` will be applied in the next use of the `brackets` function.


### `brackets.split` function (private)
### `split` function (private)

_Syntax:_ `brackets.split( template [, brackets_array] ) : Array`

Used by tmpl and riot-compiler.


### `brackets.array` function (private)
### `array` function (private)

_Syntax:_ `brackets.array( [brackets_string] ) : Array`

Used by riot-compiler.


### `brackets.R_MLCOMMS` property
### `hasExpr` function

_usage:_ `brackets.hasExpr( str )`

Checks for an expression within a string, using the current brackets.

_parameters_

* `str` : string - String where to search

_returns:_ boolean - `true` if the string contains an expression

NOTE: This function only checks for a pair of unescaped riot brackets, does not validate
the expression nor excludes brackets within quotes.


### `loopKeys` function (private)

_usage:_ `brackets.loopKeys( expr )`

Used by browser/tag/each.js

Parses the `expr` string to detect how to map the collection data to the child tags.
If the received string does not contains an expression, the behavior is undefined.

_parameters_

* `expr` : string - value of the `each` attribute

_returns:_ object - object needed to check how the items in the collection should be mapped to the child tags


### `R_MLCOMMS` property

_Type:_ RegExp

Used by internal functions and shared with the riot compiler, matches valid, multiline JavaScript comments in almost all forms. Can handle embedded sequences `/*`, `*\/` and `//` in these. Skips non-valid comments like `/*/`.
Used by internal functions and shared with the riot compiler, matches valid, multiline JavaScript comments in almost all forms. Can handle embedded sequences `/*`, `*\/` and `//` in these. Skips non-valid comments like `/*/`.

`R_MLCOMMS` does not make captures.


### `brackets.R_STRINGS` property
### `R_STRINGS` property

_Type:_ RegExp

Used by internal functions and shared with the riot compiler, matches single or double quoted strings, handles embedded quotes and multi-line strings (not in accordance with the JavaScript specs). It is not for ES6 template strings, these are too complex for a regex.
Used by internal functions and shared with the riot compiler, matches single or double quoted strings, handles embedded quotes and multi-line strings (not in accordance with the JavaScript spec). It is not for ES6 template strings, these are too complex for a regex.

`R_STRINGS` does not make captures.

### `brackets.S_QBLOCK` property

### `S_QBLOCK` property

_Type:_ string

Combines the `brackets.R_STRINGS` source with regexes for matching quoted strings, division symbols, and literal regexes.
Combines the `brackets.R_STRINGS` source with regexes for matching division symbols and literal regexes.

When dealing with clean JavaScript code, i.e. without comments, this is the only string you need to instantiate your RegExp object. For code containing comments, `S_QBLOCK` needs to be combined with other regexes for exclusion of multiline and single-line comments (`MLCOMMS` is one of both).
When dealing with clean JavaScript code, i.e. without comments, this is the only string you need to instantiate your RegExp object. For code containing comments, `S_QBLOCK` needs to be combined with other regexes for exclusion of multiline and single-line comments (`MLCOMMS` can be one of both).

The `S_QBLOCK` part captures in `$1` and `$2` a single slash, depending if it matches a division symbol ($1) or a regex ($2). If there's no matches for any of these, they have empty strings.

_Example:_

```js
// We can use riot.util.brackets if riot is in context
var brackets = require('riot-tmpl').brackets

// Creates the regex, $1 encloses the whole S_QBLOCK, for easier detection
var JS_RMCOMMS = new RegExp(
'(' + brackets.S_QBLOCK + ')|' + brackets.R_MLCOMMS.source + '|//[^\r\n]*',
Expand Down
78 changes: 49 additions & 29 deletions doc/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,51 @@

I'll try to explain the reason for the some changes in tmpl 2.3.x

## Escaped brackets, backslashes, and EOLs

Escaped brackets _within expressions_ are left unescaped, except in JavaScript strings and regexes, where are preserved. So far, I have not found a case where brackets in expressions must remain escaped.

Backslashes in the HTML parts are not touched.

EOLs are normalized to `\n` in the HTML, converted to compact spaces in expressions, and preserved in JavaScript strings and regexes.

## Handling evaluation errors

The new `tmpl.errorHandler` property allows to detect errors _in the evaluation_, by setting its value to a function that receives the generated Error object, augmented with an object `riotData` containing the properties `tagName` and `_riot_id` of the context at error time.

Other (usually fatal) errors, such as "Parse Error" generated for the Function constructor, are not intercepted.

If this property is not set, or set to falsy, as in previous versions the error is silently ignored.

Example:
```html
<mytag></mytag>
<script type="riot/tag">
<mytag><p>{ foo == 'bar' }</p></mytag>
</script>
<script>
riot.util.tmpl.errorHandler = myLogger
riot.mount('*')

function myLogger(err) {
console.log(err.message + ' in ' + err.riotData.tagName)
}
</script>
```
outputs "Cannot read property 'bar' of undefined in MYTAG" in the console.

Ref: [riot#871](https://github.com/riot/riot/issues/871), [riot#1189](https://github.com/riot/riot/issues/1189)

## The new brackets function

brackets 2.3 combines the behavior of brackets 2.2 with a new one, based on a function to make immediate, more secure changes to custom brackets. There is a performance penalty in supporting both schemes, but compatibility is maintained.

If riot is available when `brackets` is instantiated, `brackets` will use the configuration in `riot.settings`. If not, you can link a configuration later, through the new `brackets.settings` property, which accepts a reference to `riot.settings` or other object where read and write new brackets values. In this way, brackets works as in previous versions.

The other, recommended option, is call to the new `breackets.set` function with the value for the brackets. The only difference is `brackets.set` checks and make the changes immediately, while using the `settings` property the reconfiguration is delayed to first use.

It is all, syntax and behavior are the same as older versions: `brackets(regex_or_number)`.

## Characters not allowed in brackets

There are characters not allowed to define brackets, some are common characters in JavaScript expressions that hinder finding the right riot brackets, and other are forbidden by the HTML specs for text elements.
Expand Down Expand Up @@ -33,40 +78,15 @@ Source &#x2013;> | Browser &#x2013;> | riot parser &#x2013;>

Here the browser (some version of IE) receives invalid markup and try to render the best it can without break the page (i.e. "fix" the error). riot has no chance to get the expression and re-render the value. Other browser _can_ keep the markup as-is depending on its location in the elements. Anyway, the result is unpredictable.

## Escaped brackets, backslashes, and EOLs

Escaped brackets _within expressions_ are left unescaped, except in JavaScript strings and regular expressions, where are not touched. So far, I have not found a case where the brackets must remain escaped.

Other backslashes in the HTML parts, strings, and regexes, are preserved.

EOLs are normalized to `\n` in the HTML, converted to compact spaces in expressions, and preserved in JavaScript strings and regexes.

## Handling evaluation errors

The new `tmpl.errorHandler` property allows to detect errors _in the evaluation_, by setting its value to a function that receives the generated Error object, augmented with an object `riotData` containing the properties `tagName` and `\_riot_id` of the context at error time.

Other (usually fatal) errors, such as "Parse Error" generated for the Function constructor, are not intercepted.

If this property is not set, or set to falsy, as in previous versions the error is silently ignored.

## Why to use tmpl.hasExpr and tmpl.loopKeys?
## Why to use brackets.hasExpr and brackets.loopKeys?

Encapsulation. Changes to the internal `tmpl` or `brackets` function are easy if other code don't depends on the format of parsed expressions. `hasExpr` and `loopKeys` has optimized regexes to do the work and the riot code can stay a bit clearer.

`tmpl.hasExpr` is intended for general use, while `loopKeys` is useful only for riot.

## The new brackets function

In my personal opinion this function must have been designed as an array from the beginning, configured by riot at the instantiation time, and from the user via an explicit function call, without the possibility of further changes; plus an auxiliary function to convert custom regexes.

brackets 2.3 combines the behavior of brackets 2.2 with a new one, based on these idea. There is a performance penalty in supporting both but compatibility is maintained.
`brackets.hasExpr` is intended for general use, while `brackets.loopKeys` is useful only for riot.

If riot is available when `brackets` is instantiated, `brackets` will use the configuration in `riot.settings`. If not, you can link a configuration later, through the new `brackets.settings` property, which accepts a reference to `riot.settings` or other object where read and write new brackets values.
## Final Note

The other, recommended option, is call to the new `breackets.set` function with the value for the brackets. The only difference is `brackets.set` checks and make the changes immediately, while using the `settings` property the reconfiguration is delayed to first use.
There's more new functions and properties added to `brackets`, you can use [hasExpr](https://github.com/riot/tmpl/blob/dev/doc/API.md#hasexpr-function) and the [regexes](https://github.com/riot/tmpl/blob/dev/doc/API.md#r_mlcomms-property) which will be maintained, but the additional functions are for internal use.

There's more new functions and properties added to `brackets`, you can use the regexes, these will be maintained, but the additional functions are for internal use.

It is all, syntax and behavior are the same as older versions: `brackets(regex_or_number)`.

_@amarcruz_
5 changes: 3 additions & 2 deletions lib/brackets.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*
* `brackets ` Returns a string or regex based on its parameter
* `brackets.settings` Mirrors the `riot.settings` object
* `brackets.set ` The recommended option to change the current tiot brackets
* `brackets.set ` The recommended form to change the current riot brackets
*/

//#set $_RIX_TEST = 4
Expand Down Expand Up @@ -125,7 +125,8 @@ var brackets = (function (UNDEF) {
_pairs = bp.concat(pair.replace(/(?=[[\]()*+?.^$|])/g, '\\').split(' '))
_regex = _rewrite
}
_pairs[$_RIX_TEST] = _regex(_pairs[1].length > 1 ? /(?:^|[^\\]){[\S\s]*?}/ : /(?:^|[^\\]){[^}]*}/)
//_pairs[$_RIX_TEST] = _regex(_pairs[1].length > 1 ? /(?:^|[^\\]){[\S\s]*?}/ : /(?:^|[^\\]){[^}]*}/)
_pairs[$_RIX_TEST] = _regex(_pairs[1].length > 1 ? /{[\S\s]*?}/ : /{[^}]*}/)
_pairs[$_RIX_ESC] = _regex(/\\({|})/g)
_pairs[$_RIX_OPEN] = _regex(/(\\?)({)/g) // for _split()
_pairs[$_RIX_CLOSE] = _regExp('(\\\\?)(?:([[({])|(' + _pairs[3] + '))|' + S_QBSRC, REGLOB)
Expand Down
Loading