@@ -4,7 +4,6 @@ var SourceNode = require('source-map').SourceNode;
44module . exports = function ( code , filePath ) {
55 // the file name to be used in sourcemap sources and file fields
66 filePath = ( filePath || 'file.js' ) . replace ( / \\ / g, '/' ) ;
7- var tokens = tokenize ( code ) ;
87 var mutations = [ ] ;
98
109 function checkIndex ( idx ) {
@@ -16,13 +15,32 @@ module.exports = function(code, filePath) {
1615 }
1716 }
1817
18+ function checkOverlap ( start , end , str ) {
19+ var i = 0 , ii = mutations . length , mutation ;
20+ for ( ; i < ii ; i ++ ) {
21+ mutation = mutations [ i ] ;
22+ // don't check insertion against insertion
23+ if ( mutation . start === mutation . end && start === end ) continue ;
24+ if ( mutation . start < end && mutation . end > start ) {
25+ throw new Error ( 'Conflict! new mutation: start=' + mutation . start +
26+ ' end=' + mutation . end + ' str=' + mutation . value + ' ' +
27+ 'with existing mutation: start=' + start +
28+ ' end=' + end + ' str=' + str ) ;
29+
30+ }
31+ }
32+ }
33+
1934 function replace ( start , end , str ) {
2035 var existing ;
2136 checkIndex ( start ) ;
2237 checkIndex ( end ) ;
38+ checkOverlap ( start , end , str ) ;
39+
2340 if ( end < start ) {
2441 throw new Error ( 'end-index: ' + end + ' cannot be smaller than start-index: ' + start ) ;
2542 }
43+
2644 if ( start === end ) {
2745 // allow multiple insertion to same location
2846 existing = mutations . find ( function ( m ) {
@@ -42,32 +60,35 @@ module.exports = function(code, filePath) {
4260 modifyCode . prepend = function ( str ) {
4361 return replace ( 0 , 0 , str ) ;
4462 } ;
63+
4564 modifyCode . append = function ( str ) {
4665 return replace ( code . length , code . length , str ) ;
4766 } ;
67+
4868 modifyCode . insert = function ( start , str ) {
4969 return replace ( start , start , str ) ;
5070 } ;
71+
5172 modifyCode . replace = function ( start , end , str ) {
5273 return replace ( start , end , str ) ;
5374 } ;
75+
5476 modifyCode . delete = function ( start , end ) {
5577 return replace ( start , end , '' ) ;
5678 } ;
79+
5780 modifyCode . transform = function ( ) {
5881 var i = 0 , ti = 0 , ii = mutations . length , newTokens = [ ] ;
59- var mutation , newValue , offset , offset2 , merged ;
60-
61- function advance ( ) { if ( ti < tokens . length ) ti ++ ; }
62- function token ( ) { return tokens [ ti ] ; }
63- function prev ( ) { return tokens [ ti - 1 ] ; }
82+ var mutation , offset , offset2 , merged , isInsertion ;
83+ var tokens = tokenize ( code ) ;
6484
6585 mutations . sort ( function ( a , b ) { return a . start - b . start ; } ) ;
6686
6787 for ( ; i < ii ; i ++ ) {
6888 mutation = mutations [ i ] ;
89+ isInsertion = mutation . start === mutation . end ;
6990
70- if ( token ( ) && token ( ) . start > mutation . start ) {
91+ if ( tokens [ ti ] && tokens [ ti ] . start > mutation . start ) {
7192 if ( newTokens . length && newTokens [ newTokens . length - 1 ] . start <= mutation . start ) {
7293 throw new Error ( 'does not allow mutating same token again. Token affected: ' +
7394 JSON . stringify ( newTokens [ newTokens . length - 1 ] . value ) ) ;
@@ -76,79 +97,66 @@ module.exports = function(code, filePath) {
7697 }
7798 } else {
7899 // move to current affected token
79- while ( token ( ) && token ( ) . end <= mutation . start ) {
80- newTokens . push ( token ( ) ) ;
81- advance ( ) ;
100+ while ( tokens [ ti ] && ( isInsertion ?
101+ tokens [ ti ] . end < mutation . start :
102+ tokens [ ti ] . end <= mutation . start // push replacement to next token
103+ ) ) {
104+ newTokens . push ( tokens [ ti ] ) ;
105+ ti ++ ;
82106 }
83107 }
84108
85- if ( mutation . start === mutation . end ) {
109+ if ( isInsertion ) {
86110 // an insertion
87- if ( ! token ( ) ) {
88- // append
89- newTokens . push ( {
90- value : mutation . value ,
91- start : mutation . start ,
92- end : mutation . end ,
93- line : prev ( ) ? prev ( ) . endLine : 1 ,
94- column : prev ( ) ? prev ( ) . endColumn : 0
95- } ) ;
96- } else if ( token ( ) . start === mutation . start ) {
97- // prepend or insert
98- newTokens . push ( {
99- value : mutation . value ,
100- start : mutation . start ,
101- end : mutation . end ,
102- line : token ( ) . line ,
103- column : token ( ) . column
104- } ) ;
105- newTokens . push ( token ( ) ) ;
106- advance ( ) ;
111+ if ( ! tokens [ ti ] ) {
112+ // this can only happen when
113+ // 1. empty code where tokens size is zero.
114+ // 2. append in the end
115+ if ( mutation . start === 0 ) {
116+ newTokens . push ( {
117+ value : mutation . value ,
118+ start : 0 ,
119+ end : 0 ,
120+ line : 1 ,
121+ column : 0
122+ } ) ;
123+ } else if ( newTokens . length && newTokens [ newTokens . length - 1 ] . end === mutation . start ) {
124+ newTokens [ newTokens . length - 1 ] . value += mutation . value ;
125+ } else {
126+ panic ( mutation ) ;
127+ }
107128 } else {
108129 // insertion in this token
109- offset = mutation . start - token ( ) . start ;
110- newValue = token ( ) . value . slice ( 0 , offset ) + mutation . value + token ( ) . value . slice ( offset ) ;
111- newTokens . push ( {
112- value : newValue ,
113- start : token ( ) . start ,
114- end : token ( ) . end ,
115- line : token ( ) . line ,
116- column : token ( ) . column
117- } ) ;
118- advance ( ) ;
130+ offset = mutation . start - tokens [ ti ] . start ;
131+ tokens [ ti ] . value = tokens [ ti ] . value . slice ( 0 , offset ) + mutation . value + tokens [ ti ] . value . slice ( offset ) ;
132+ newTokens . push ( tokens [ ti ] ) ;
133+ ti ++ ;
119134 }
120135 } else {
121136 // a replacement
122- if ( ! token ( ) ) panic ( mutation ) ;
137+ if ( ! tokens [ ti ] ) panic ( mutation ) ;
123138
124139 // merge tokens if replacement affects multiple tokens
125- merged = {
126- value : token ( ) . value ,
127- start : token ( ) . start ,
128- end : token ( ) . end ,
129- line : token ( ) . line ,
130- column : token ( ) . column
131- } ;
132-
140+ merged = tokens [ ti ] ;
133141 while ( merged . end < mutation . end ) {
134- advance ( ) ;
135- if ( ! token ( ) ) panic ( mutation ) ;
136- merged . value = merged . value + token ( ) . value ;
137- merged . end = token ( ) . end ;
142+ ti ++ ;
143+ if ( ! tokens [ ti ] ) panic ( mutation ) ;
144+ merged . value = merged . value + tokens [ ti ] . value ;
145+ merged . end = tokens [ ti ] . end ;
138146 }
139147
140148 offset = mutation . start - merged . start ;
141149 offset2 = mutation . end - merged . start ;
142150 merged . value = merged . value . slice ( 0 , offset ) + mutation . value + merged . value . slice ( offset2 ) ;
143151 newTokens . push ( merged ) ;
144- advance ( ) ;
152+ ti ++ ;
145153 }
146154 }
147155
148156 // the rest unaffected tokens
149- while ( token ( ) ) {
150- newTokens . push ( token ( ) ) ;
151- advance ( ) ;
157+ while ( tokens [ ti ] ) {
158+ newTokens . push ( tokens [ ti ] ) ;
159+ ti ++ ;
152160 }
153161
154162 var node = new SourceNode ( null , null , null , newTokens . map ( function ( t ) {
@@ -168,5 +176,6 @@ module.exports = function(code, filePath) {
168176} ;
169177
170178function panic ( mutation ) {
171- throw new Error ( 'Panic! mutation: start=' + mutation . start + ' end=' + mutation . end + ' str=' + mutation . value ) ;
179+ throw new Error ( 'Panic! mutation: start=' + mutation . start +
180+ ' end=' + mutation . end + ' str=' + mutation . value ) ;
172181}
0 commit comments