Skip to content

Commit

Permalink
ES6 modules, limited support.
Browse files Browse the repository at this point in the history
Add support for es6 `import` statements. Thanks to @kuashe!

Related to [riot#1715](riot/riot#1715), [riot#1784](riot/riot#1784), and [riot#1864](riot/riot#1864).
  • Loading branch information
amarcruz committed Aug 30, 2016
1 parent 77050ad commit b5f870c
Show file tree
Hide file tree
Showing 13 changed files with 63 additions and 100 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.yml
Expand Up @@ -134,7 +134,7 @@ rules:
keyword-spacing: 2 # enforce spacing before and after keywords
linebreak-style: [2, "unix"]
max-depth: [1, 5] # specify the maximum depth blocks can be nested
max-len: [1, 92, 4, { "ignoreTrailingComments": true, "ignoreUrls": true, "ignorePattern": "=\\s+/|_regEx\\(|RegExp\\(" }]
max-len: [1, 96, 4, { "ignoreTrailingComments": true, "ignoreUrls": true, "ignorePattern": "=\\s+/|_regEx\\(|RegExp\\(" }]
no-control-regex: 1
# maximum line length, except for regexes
max-nested-callbacks: [2, 4] # specify the maximum depth callbacks can be nested (Default: [0, 2])
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,7 @@

### v2.5.4
- Added parser for [bublé](https://buble.surge.sh) as `buble`.
- Added support for es6 `import` statements. Thanks to @kuashe! - Related to [riot#1715](https://github.com/riot/riot/issues/1715), [riot#1784](https://github.com/riot/riot/issues/1784), and [riot#1864](https://github.com/riot/riot/issues/1864).

### v2.5.3
- Fix #73 : resolveModuleSource must be a function - Option removed from the default Babel options.
Expand Down
25 changes: 7 additions & 18 deletions dist/es6.compiler.js
Expand Up @@ -164,7 +164,7 @@ var PRE_TAGS = /<pre(?:\s+(?:[^">]*|"[^"]*")*)?>([\S\s]+?)<\/pre\s*>/gi

var SPEC_TYPES = /^"(?:number|date(?:time)?|time|month|email|color)\b/i

var IMPORT_STATEMENT = /^(?: )*(?:import)(?:(?:.*))*$/gm
var IMPORT_STATEMENT = /^\s*import(?:\s*[*{]|\s+[$_a-zA-Z'"]).*\n?/gm

var TRIM_TRAIL = /[ \t]+$/gm

Expand Down Expand Up @@ -274,20 +274,6 @@ function restoreExpr (html, pcex) {
return html
}

function compileImports (js) {
var imp = []
var imports = ''
while (imp = IMPORT_STATEMENT.exec(js)) {
imports += imp[0].trim() + '\n'
}
return imports
}

function rmImports (js) {
var jsCode = js.replace(IMPORT_STATEMENT, '')
return jsCode
}

function _compileHTML (html, opts, pcex) {

html = splitHtml(html, opts, pcex)
Expand Down Expand Up @@ -689,9 +675,11 @@ function compile (src, opts, url) {

if (included('js')) {
body = _compileJS(blocks[1], opts, null, null, url)
imports = compileImports(jscode)
jscode = rmImports(jscode)
if (body) jscode += (jscode ? '\n' : '') + body
jscode = jscode.replace(IMPORT_STATEMENT, function (s) {
imports += s.trim() + '\n'
return ''
})
}
}
}
Expand All @@ -704,7 +692,8 @@ function compile (src, opts, url) {
html: html,
css: styles,
attribs: attribs,
js: jscode
js: jscode,
imports: imports
})
return ''
}
Expand Down
25 changes: 7 additions & 18 deletions dist/riot.compiler.js
Expand Up @@ -162,7 +162,7 @@ var compile = (function () {

var SPEC_TYPES = /^"(?:number|date(?:time)?|time|month|email|color)\b/i

var IMPORT_STATEMENT = /^(?: )*(?:import)(?:(?:.*))*$/gm
var IMPORT_STATEMENT = /^\s*import(?:\s*[*{]|\s+[$_a-zA-Z'"]).*\n?/gm

var TRIM_TRAIL = /[ \t]+$/gm

Expand Down Expand Up @@ -272,20 +272,6 @@ var compile = (function () {
return html
}

function compileImports (js) {
var imp = []
var imports = ''
while (imp = IMPORT_STATEMENT.exec(js)) {
imports += imp[0].trim() + '\n'
}
return imports
}

function rmImports (js) {
var jsCode = js.replace(IMPORT_STATEMENT, '')
return jsCode
}

function _compileHTML (html, opts, pcex) {

html = splitHtml(html, opts, pcex)
Expand Down Expand Up @@ -687,9 +673,11 @@ var compile = (function () {

if (included('js')) {
body = _compileJS(blocks[1], opts, null, null, url)
imports = compileImports(jscode)
jscode = rmImports(jscode)
if (body) jscode += (jscode ? '\n' : '') + body
jscode = jscode.replace(IMPORT_STATEMENT, function (s) {
imports += s.trim() + '\n'
return ''
})
}
}
}
Expand All @@ -702,7 +690,8 @@ var compile = (function () {
html: html,
css: styles,
attribs: attribs,
js: jscode
js: jscode,
imports: imports
})
return ''
}
Expand Down
1 change: 1 addition & 0 deletions doc/README.md
Expand Up @@ -159,6 +159,7 @@ The predefined parsers are:
- `typescript`
- `es6` - (using `babel-core` or `babel`)
- `babel` - (using `babel-core` v6.x and the `es2015` preset)
- `buble`
- `coffee` or `coffeescript`
## Changes in v2.3.0
Expand Down
23 changes: 18 additions & 5 deletions doc/guide.md
Expand Up @@ -150,7 +150,7 @@ The `compile` and `riot.compile` functions can take an additional parameter spec
| compact | html | boolean | Remove spaces between tags (minify `<p> </p> <p> </p>` to `<p></p><p></p>`)
| whitespace | html | boolean | Preserve newlines and tabs. newlines are normalized anyway
| template | html | string | HTML pre-processor. Built-in support for: jade
| type | js | string | JavaScript pre-processor. Built-in support for: es6, babel, coffeescript, typescript, livescript, none (no preprocess)
| type | js | string | JavaScript pre-processor. Built-in support for: es6, babel, buble, coffeescript, typescript, livescript, none (no preprocess)
| style | css | string | CSS pre-processor. Built-in support for: sass, scss, less, stylus (only less in browsers)
| entities | compile | boolean | Split the tag in its raw parts.
| exclude | compile | array | This is an array of strings with part names to exclude. These names are the same as those generated by the `entities` option: html, css, attribs, js. Ej. `{exclude: ['js']}`
Expand All @@ -160,6 +160,8 @@ The `compile` and `riot.compile` functions can take an additional parameter spec
This option, new in v2.3.13, causes the `compile` function return an array of objects with the parts of the tags.
Each object contains five properties: tagName, html, attribs, css, and js. Propertie values for non-existent parts are empty strings.

From v2.5.4, `entities` includes the `import` declarations as a multiline string.

Example:
```html
<script type="riot/tag" id="test1">
Expand All @@ -168,6 +170,7 @@ Example:
<tag2>
<style>#id1 {top:0}</style>
<p/>
import * as foo from "./module"
click(e) {
}
</tag2>
Expand All @@ -181,7 +184,7 @@ will set `arr` to be:
```js
[
{tagName: 'tag1', html: '<div></div>', css: '', attribs: 'id="id1"', js: ''},
{tagName: 'tag2', html: '<p></p>', css: '#id1 {top:0}', attribs: '', js: ' this.click = function(e) {\n }.bind(this);' }
{tagName: 'tag2', html: '<p></p>', css: '#id1 {top:0}', attribs: '', js: ' this.click = function(e) {\n }.bind(this);', imports: 'import * as foo from "./module"\n' }
]
```

Expand Down Expand Up @@ -253,6 +256,16 @@ Following the above rules, detect the last HTML tag is not difficult, but keep i
```
The compiler does not recognize template strings and confuses `<p>` with the last HTML element.


### ES6 modules

From v2.5.4 the riot-compiler offers limited support for ES6 modules (`import` declarations are hoisted and each must be written in one line).
Also, the `entities` option returns the declarations as one multiline string.

**Note:** An `import` declaration must not spawn multiple lines.

See [Chapter 16 Modules](http://exploringjs.com/es6/ch_modules.html) of Exploring ES6.

### Multiple JavaScript Blocks

Each JavaScript block in the tag can have different `type` attributes.
Expand All @@ -268,7 +281,7 @@ The filename in `src` can be absolute or relative. If you pass a third parameter
Without a `type=` directive, the JavaScript parser defaults to the `type` specified in the options passed to the compiler. If you don't want the code to be parsed, use `type="none"`.

If you just want to get the `script` tag rendered, keeping the `type`
attribute and the tag contents untouched, you should then use the `defer`
attribute and the tag contents untouched, you should then use the `defer`
attribute.

The `defer` attribute is used to avoid the processing of the `script` tag
Expand Down Expand Up @@ -389,9 +402,9 @@ The `parserOpts` and `url` properties of _extraOptions_ will be passed to the gi
Example:
```js
var opts = {url: url},
css = compiler.js(code, 'babel', opts)
css = compiler.js(code, 'buble', opts)
```
will run `parsers.js.babel(code, opts.parserOpts, opts.url)` (inside the parser, the url will be passed as `{filename: url}` to babel).
will run `parsers.js.buble(code, opts.parserOpts, opts.url)` (inside the parser, the url will be passed as `{source: url}` to bublé).

**Note:**
If you omit `parserName` but include `extraOptions`, you **must** include `compilerOptions` as well:
Expand Down
35 changes: 7 additions & 28 deletions lib/compiler.js
Expand Up @@ -118,7 +118,7 @@ var SPEC_TYPES = /^"(?:number|date(?:time)?|time|month|email|color)\b/i
* Matches the 'import' statement
* @const {RegExp}
*/
var IMPORT_STATEMENT = /^(?: )*(?:import)(?:(?:.*))*$/gm
var IMPORT_STATEMENT = /^\s*import(?:\s*[*{]|\s+[$_a-zA-Z'"]).*\n?/gm

/**
* Matches trailing spaces and tabs by line.
Expand Down Expand Up @@ -269,30 +269,6 @@ function restoreExpr (html, pcex) {
return html
}

/**
* Return imports statement of the code as a string
* @param {string} js - The js code containing the imports statement
* @returns {string} Js code containing only the imports statement
*/
function compileImports (js) {
var imp = []
var imports = ''
while (imp = IMPORT_STATEMENT.exec(js)) {
imports += imp[0].trim() + '\n'
}
return imports
}

/**
* Remove 'import' statement from JSCode
* @param {string} js - The Js code
* @returns {string} jsCode The js code without 'import' statement
*/
function rmImports (js) {
var jsCode = js.replace(IMPORT_STATEMENT, '')
return jsCode
}

/**
* The internal HTML compiler.
*
Expand Down Expand Up @@ -996,9 +972,11 @@ function compile (src, opts, url) {

if (included('js')) {
body = _compileJS(blocks[1], opts, null, null, url)
imports = compileImports(jscode)
jscode = rmImports(jscode)
if (body) jscode += (jscode ? '\n' : '') + body
jscode = jscode.replace(IMPORT_STATEMENT, function (s) {
imports += s.trim() + '\n'
return ''
})
}
}
}
Expand All @@ -1011,7 +989,8 @@ function compile (src, opts, url) {
html: html,
css: styles,
attribs: attribs,
js: jscode
js: jscode,
imports: imports
})
return ''
}
Expand Down
35 changes: 7 additions & 28 deletions src/core.js
Expand Up @@ -130,7 +130,7 @@ var SPEC_TYPES = /^"(?:number|date(?:time)?|time|month|email|color)\b/i
* Matches the 'import' statement
* @const {RegExp}
*/
var IMPORT_STATEMENT = /^(?: )*(?:import)(?:(?:.*))*$/gm
var IMPORT_STATEMENT = /^\s*import(?:\s*[*{]|\s+[$_a-zA-Z'"]).*\n?/gm

/**
* Matches trailing spaces and tabs by line.
Expand Down Expand Up @@ -283,30 +283,6 @@ function restoreExpr (html, pcex) {
return html
}

/**
* Return imports statement of the code as a string
* @param {string} js - The js code containing the imports statement
* @returns {string} Js code containing only the imports statement
*/
function compileImports (js) {
var imp = []
var imports = ''
while (imp = IMPORT_STATEMENT.exec(js)) {
imports += imp[0].trim() + '\n'
}
return imports
}

/**
* Remove 'import' statement from JSCode
* @param {string} js - The Js code
* @returns {string} jsCode The js code without 'import' statement
*/
function rmImports (js) {
var jsCode = js.replace(IMPORT_STATEMENT, '')
return jsCode
}

/*
HTML Compiler
-----------------------------------------------------------------------------
Expand Down Expand Up @@ -1091,9 +1067,11 @@ function compile (src, opts, url) {
// and the untagged js block
if (included('js')) {
body = _compileJS(blocks[1], opts, null, null, url)
imports = compileImports(jscode)
jscode = rmImports(jscode)
if (body) jscode += (jscode ? '\n' : '') + body
jscode = jscode.replace(IMPORT_STATEMENT, function (s) {
imports += s.trim() + '\n'
return ''
})
}
}
}
Expand All @@ -1108,7 +1086,8 @@ function compile (src, opts, url) {
html: html,
css: styles,
attribs: attribs,
js: jscode
js: jscode,
imports: imports
})
return ''
}
Expand Down
4 changes: 4 additions & 0 deletions test/specs/expect/es6-import-untagged.js
@@ -0,0 +1,4 @@
import* as foo from 'doe'
import 'bar'
riot.tag2('import-untagged', '<h1>Hello</h1>', '', '', function(opts) {
});
2 changes: 1 addition & 1 deletion test/specs/expect/es6-import.js
@@ -1,6 +1,6 @@
import john from 'doe'
import foo from 'bar'
import{foo, bar, baz } from 'foo.bar.baz'
import { foo, bar, baz } from 'foo.bar.baz'
riot.tag2('import', '<h1>Hello</h1>', '', '', function(opts){
this.time = function(){
return Date()
Expand Down
5 changes: 5 additions & 0 deletions test/specs/fixtures/es6-import-untagged.tag
@@ -0,0 +1,5 @@
<import-untagged>
<h1>Hello</h1>
import* as foo from 'doe'
import 'bar'
</import-untagged>
1 change: 0 additions & 1 deletion test/specs/fixtures/es6-import.tag
Expand Up @@ -5,7 +5,6 @@
import john from 'doe'
import foo from 'bar'
import { foo, bar, baz } from 'foo.bar.baz'

time(){
return Date()
}
Expand Down
4 changes: 4 additions & 0 deletions test/specs/tag.js
Expand Up @@ -75,6 +75,10 @@ describe('Compile tags', function () {
testFile('es6-import')
})

it('Detect es6 import in the untagged JS block', function () {
testFile('es6-import-untagged')
})

it('Flexible method style (v2.3)', function () {
testFile('free-style')
})
Expand Down

0 comments on commit b5f870c

Please sign in to comment.