added test case for sourcemap
diff --git a/src/map.js b/src/map.js
index 6a925dd..b859690 100644
--- a/src/map.js
+++ b/src/map.js
@@ -26,6 +26,7 @@
const current = this.current
this.current = {}
+ // re-order the elements and scripts into history
const length = current.elements.length
if (length > 0) {
const children = this.history.splice(-length, length)
@@ -50,10 +51,12 @@
if (!this.enabled) { return }
this.current.elements.push({ name, index, line, length })
}
+
addScript (name, info, externalOffset) {
if (!this.enabled) { return }
this.current.scripts.push({ name, info, externalOffset })
}
+
setElementPosition (name, line, column) {
if (!this.enabled) { return }
this.elements[name] = { line, column }
@@ -73,9 +76,9 @@
const { original, generated } = info
const scriptLength = info.length
this.add(
- original.line + (elInfo.line || 1) - 2,
+ original.line + (elInfo.line || 1) - 1,
scriptLength,
- generated.line + startLine + (line || 1) + externalOffset
+ generated.line + startLine + (line || 1) - 1 + externalOffset
)
});
diff --git a/src/parser.js b/src/parser.js
index 24910de..03b9a80 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -60,6 +60,7 @@
const elPromises = []
Object.keys(elements).forEach(key => {
const el = elements[key]
+ // record original positions of each <element>
map.setElementPosition(el.name, el.line, el.column)
elPromises.push(parseWeex(loader, params, el.content, map, deps, el.name))
})
@@ -98,17 +99,23 @@
const mapOffset = { basic: 0, subs: [] }
if (scripts) {
- content += scripts.reduce((pre, cur) => {
- const line = pre.split(/\r?\n/g).length
+ // record original and generated position of each <script>
+ // the generated content is begin with empty string
+ // so later the template, styles and elements will be appended/prepended
+ // and mapOffset.basic will record lines of prepended *required* content
+ content += scripts.reduce((prev, next, i) => {
+ // length of previous content
+ const line = prev.split(/\r?\n/g).length + 1
const column = 1
- const oriLine = cur.line - 1
- const oriColumn = cur.column
+ const oriLine = next.line
+ const oriColumn = next.column
mapOffset.subs.push({
original: { line: oriLine, column: oriColumn },
generated: { line, column },
- length: cur.content.split(/\r?\n/g).length
+ // length of next content
+ length: next.content.split(/\r?\n/g).length
})
- return pre + '\n;' + cur.content
+ return prev + '\n;' + next.content
}, '')
}
@@ -118,27 +125,32 @@
depHasRequired(content, dep) ? 'require("' + dep + '");' : ''
).join('\n')
if (requireContent) {
- content = requireContent + '\n' + content
+ // length of implicitly requires
mapOffset.basic = requireContent.split(/\r?\n/g).length
+ content = requireContent + '\n' + content
}
}
if (template) {
+ // append template content, not impact sourcemap
content += '\n;module.exports.template = module.exports.template || {}' +
'\n;Object.assign(module.exports.template, ' + template + ')'
}
if (style) {
+ // append style content, not impact sourcemap
content += '\n;module.exports.style = module.exports.style || {}' +
'\n;Object.assign(module.exports.style, ' + style + ')'
}
+ // prepare entry config
if (configResult) {
config = new Function('return ' + configResult.content.replace(/\n/g, ''))()
}
config.transformerVersion = transformerVersion
config = JSON.stringify(config, null, 2)
+ // prepare entry data
if (dataResult) {
data = new Function('return ' + dataResult.content.replace(/\n/g, ''))()
data = JSON.stringify(data, null, 2)
@@ -201,11 +213,14 @@
: (elementName || params.resourceQuery.name || getNameByPath(params.resourcePath))
// join with elements deps
- // 2 more lines at end
+ // 2 more lines between each element and the end
map && map.start()
- const prefix = (elements || []).reduce((current, next, index) => {
- map && map.addElement(name, index, current.split(/\r?\n/g).length, next.split(/\r?\n/g).length)
- return current + next + ';\n\n'
+ const prefix = (elements || []).reduce((prev, next, index) => {
+ const prevLength = prev.split(/\r?\n/g).length
+ const nextLength = next.split(/\r?\n/g).length
+ // record generated positions of each <element>
+ map && map.addElement(name, index, prevLength, nextLength)
+ return prev + next + ';\n\n'
}, '')
// fix data option from an object to a function
@@ -219,12 +234,19 @@
target = ';__weex_define__("@weex-component/' + name + '", [], ' +
'function(__weex_require__, __weex_exports__, __weex_module__)' +
'{\n' + target + '\n})'
- mapOffset && mapOffset.subs.forEach(info => {
- map.addScript(elementName || name, info, prefix.split(/\r?\n/g).length + mapOffset.basic)
- })
+
+ // record mapOffset into sourcemap
+ if (mapOffset) {
+ // length of generated prefix (elements) and basic (implicitly requires)
+ const preLines = prefix.split(/\r?\n/g).length + mapOffset.basic
+ mapOffset.subs.forEach(info => {
+ map.addScript(elementName || name, info, preLines)
+ })
+ }
map && map.end()
// append __weex_bootstrap__ for entry component
+ // not impact sourcemap
if (isEntry) {
target += '\n;__weex_bootstrap__("@weex-component/' + name + '", ' +
String(config) + ',' +
diff --git a/test/a.js b/test/a.js
index b8f9f49..574e715 100644
--- a/test/a.js
+++ b/test/a.js
@@ -10,4 +10,4 @@
}
module.exports.style = require('./a.less');
-module.exports.template = require('./a.tpl');
\ No newline at end of file
+module.exports.template = require('./a.tpl');
diff --git a/test/expect/a.we b/test/expect/a.we
index 2ea3b36..2565076 100644
--- a/test/expect/a.we
+++ b/test/expect/a.we
@@ -24,4 +24,4 @@
text: 'Hello ' + c.name
}
}
-</script>
\ No newline at end of file
+</script>
diff --git a/test/expect/sourcemap.we b/test/expect/sourcemap.we
new file mode 100644
index 0000000..f798f7f
--- /dev/null
+++ b/test/expect/sourcemap.we
@@ -0,0 +1,26 @@
+<element name="foo">
+ <template>
+ <text>Hello</text>
+ </template>
+ <script>
+ console.log(6)
+ console.log(7)
+ console.log(8)
+ console.log(9)
+ console.log(0)
+ </script>
+</element>
+
+<template>
+ <div>
+ <foo></foo>
+ </div>
+</template>
+
+<script>
+ console.log(1)
+ console.log(2)
+ require('../lib/3rd.js')
+ console.log(4)
+ console.log(5)
+</script>
diff --git a/test/lib/3rd.js b/test/lib/3rd.js
index e132ec8..cc00e41 100644
--- a/test/lib/3rd.js
+++ b/test/lib/3rd.js
@@ -1 +1,4 @@
'Hello 3rd-party JavaScript'
+'Hello 3rd-party JavaScript 2'
+'Hello 3rd-party JavaScript 3'
+'Hello 3rd-party JavaScript 4'
diff --git a/test/test.js b/test/test.js
index ab14972..e2a616d 100644
--- a/test/test.js
+++ b/test/test.js
@@ -7,6 +7,9 @@
var expect = chai.expect;
chai.use(sinonChai);
+var webpack = require('webpack')
+var SourceMapConsumer = require('source-map').SourceMapConsumer
+
require('./lib/jsfm');
var createInstance = global.createInstance;
var getRoot = global.getRoot;
@@ -25,10 +28,10 @@
var name = 'a.js';
var actualCodePath = path.resolve(__dirname, 'actual', name);
- var actualCodeContent = fs.readFileSync(actualCodePath);
+ var actualCodeContent = fs.readFileSync(actualCodePath, { encoding: 'utf8' });
var expectCodePath = path.resolve(__dirname, 'expect', name);
- var expectCodeContent = fs.readFileSync(expectCodePath);
+ var expectCodeContent = fs.readFileSync(expectCodePath, { encoding: 'utf8' });
var actualResult = createInstance('actual/' + name, actualCodeContent);
@@ -44,10 +47,10 @@
var name = 'b.js';
var actualCodePath = path.resolve(__dirname, 'actual', name);
- var actualCodeContent = fs.readFileSync(actualCodePath);
+ var actualCodeContent = fs.readFileSync(actualCodePath, { encoding: 'utf8' });
var expectCodePath = path.resolve(__dirname, 'expect', name);
- var expectCodeContent = fs.readFileSync(expectCodePath);
+ var expectCodeContent = fs.readFileSync(expectCodePath, { encoding: 'utf8' });
var actualResult = createInstance('actual/' + name, actualCodeContent);
@@ -63,10 +66,10 @@
var name = 'z.js';
var actualCodePath = path.resolve(__dirname, 'actual', name);
- var actualCodeContent = fs.readFileSync(actualCodePath);
+ var actualCodeContent = fs.readFileSync(actualCodePath, { encoding: 'utf8' });
var expectCodePath = path.resolve(__dirname, 'expect', name);
- var expectCodeContent = fs.readFileSync(expectCodePath);
+ var expectCodeContent = fs.readFileSync(expectCodePath, { encoding: 'utf8' });
var actualResult = createInstance('actual/' + name, actualCodeContent);
@@ -77,4 +80,53 @@
expect(actualJson).eql(expectJson);
});
+
+ it('support source map', function() {
+ var name = 'sourcemap'
+
+ var mapPath = path.resolve(__dirname, 'actual', name + '.js.map');
+ var map = fs.readFileSync(mapPath, { encoding: 'utf8' });
+ var smc = new SourceMapConsumer(JSON.parse(map))
+
+ var oriPath = path.resolve(__dirname, 'expect', name + '.we');
+ var ori = fs.readFileSync(oriPath, { encoding: 'utf8' });
+
+ var genPath = path.resolve(__dirname, 'actual', name + '.js');
+ var gen = fs.readFileSync(genPath, { encoding: 'utf8' });
+
+ function matchPos(code, regexp) {
+ var line, col
+ code.split(/\r?\n/g).some(function (l, i) {
+ if (regexp.test(l)) {
+ line = i + 1
+ col = l.length
+ return true
+ }
+ })
+ return { line: line, col: col }
+ }
+
+ function checkPos(regexp) {
+ var genPos = matchPos(gen, regexp)
+ var oriPos = matchPos(ori, regexp)
+
+ var pos = smc.originalPositionFor({
+ line: genPos.line,
+ column: genPos.col
+ })
+
+ expect(pos.source.indexOf('sourcemap.we') > -1)
+ expect(pos.line).to.equal(oriPos.line)
+ }
+
+ checkPos(/console\.log\(1\)/)
+ checkPos(/console\.log\(2\)/)
+ checkPos(/console\.log\(4\)/)
+ checkPos(/console\.log\(5\)/)
+ checkPos(/console\.log\(6\)/)
+ checkPos(/console\.log\(7\)/)
+ checkPos(/console\.log\(8\)/)
+ checkPos(/console\.log\(9\)/)
+ checkPos(/console\.log\(0\)/)
+ })
})
diff --git a/test/webpack.config.js b/test/webpack.config.js
index 4833d07..68792f3 100644
--- a/test/webpack.config.js
+++ b/test/webpack.config.js
@@ -2,6 +2,7 @@
module.exports = {
entry: {
+ sourcemap: path.resolve(__dirname, 'expect/sourcemap.we?entry=true'),
a: path.resolve(__dirname, 'a.js?entry=true'),
b: path.resolve(__dirname, 'expect/b.we?entry=true'),
z: path.resolve(__dirname, 'expect/z.we?entry=true')
@@ -10,6 +11,7 @@
path: path.resolve(__dirname, 'actual'),
filename: '[name].js'
},
+ devtool: 'source-map',
module: {
loaders: [
{