forked from regularjs/regular-loader
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.js
135 lines (116 loc) · 3.21 KB
/
parser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
var parse5 = require( 'parse5' );
var deindent = require( './deindent' );
var hash = require( 'hash-sum' );
var cache = require( 'lru-cache' )( 100 );
var SourceMapGenerator = require( 'source-map' ).SourceMapGenerator;
var splitRE = /\r?\n/g
var emptyRE = /^\s*$/
function getCommentSymbol() {
return '//';
}
function getAttribute( node, name ) {
if (node.attrs) {
var i = node.attrs.length
var attr
while (i--) {
attr = node.attrs[i]
if (attr.name === name) {
return attr.value
}
}
}
}
function commentScript( content ) {
var symbol = getCommentSymbol();
var lines = content.split( splitRE )
return lines.map( function( line, index ) {
// preserve EOL
if (index === lines.length - 1 && emptyRE.test( line )) {
return ''
} else {
return symbol + (emptyRE.test( line ) ? '' : ' ' + line)
}
} )
.join( '\n' )
}
function parse( content, filename, needMap ) {
var cacheKey = hash( filename + content )
// source-map cache busting for hot-reloadded modules
var filenameWithHash = filename + '?' + cacheKey
var output = cache.get( cacheKey )
if (output) return output
var output = {
template: [],
style: [],
script: [],
}
var fragment = parse5.parseFragment( content, {
locationInfo: true
} );
fragment.childNodes.forEach( function( node ) {
var tagName = node.tagName;
var lang = getAttribute( node, 'lang' );
var scoped = getAttribute( node, 'scoped' ) != null
var map = null
if (!output[tagName]) {
return;
}
if (tagName === 'template') {
node = node.content;
}
var start = node.childNodes[0].__location.startOffset;
var end = node.childNodes[node.childNodes.length - 1].__location.endOffset;
var result;
if (tagName === 'script') {
result = commentScript( content.slice( 0, start ) ) +
deindent( content.slice( start, end ) ) +
commentScript( content.slice( end ) );
} else {
var lineOffset = content.slice( 0, start ).split( splitRE ).length - 1
result = deindent( content.slice( start, end ) )
result = Array( lineOffset + 1 ).join( '\n' ) + result
}
if (needMap) {
// generate source map
map = new SourceMapGenerator()
map.setSourceContent( filenameWithHash, content )
// do not add mappings for comment lines - babel's source map
// somehow gets messed up because of it
var isCommentLine = function( line ) {
return tagName === 'script' &&
line.indexOf( getCommentSymbol() ) === 0
}
result.split( splitRE ).forEach( function( line, index ) {
if (!emptyRE.test( line ) && !isCommentLine( line )) {
map.addMapping( {
source: filenameWithHash,
original: {
line: index + 1,
column: 0
},
generated: {
line: index + 1,
column: 0
}
} )
}
} )
// workaround for Webpack eval-source-map bug
// https://github.com/webpack/webpack/pull/1816
// in case the script was piped through another loader
// that doesn't pass down the source map properly.
if (tagName === 'script' && !lang) {
result += '\n/* generated by pure-loader */\n'
}
}
output[tagName].push( {
content: result,
lang: lang,
scoped: scoped,
map: map && map.toJSON()
} );
} );
cache.set( cacheKey, output )
return output
}
module.exports = parse;