jass-vue 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +43 -0
  4. data/lib/jass/vue.rb +12 -0
  5. data/lib/jass/vue/version.rb +5 -0
  6. data/vendor/node_modules/arr-diff/index.js +58 -0
  7. data/vendor/node_modules/arr-diff/package.json +49 -0
  8. data/vendor/node_modules/arr-flatten/index.js +22 -0
  9. data/vendor/node_modules/arr-flatten/package.json +76 -0
  10. data/vendor/node_modules/array-unique/index.js +28 -0
  11. data/vendor/node_modules/array-unique/package.json +37 -0
  12. data/vendor/node_modules/braces/index.js +399 -0
  13. data/vendor/node_modules/braces/package.json +83 -0
  14. data/vendor/node_modules/de-indent/index.js +45 -0
  15. data/vendor/node_modules/de-indent/package.json +25 -0
  16. data/vendor/node_modules/de-indent/test.js +30 -0
  17. data/vendor/node_modules/estree-walker/dist/estree-walker.es.js +55 -0
  18. data/vendor/node_modules/estree-walker/dist/estree-walker.es6.js +59 -0
  19. data/vendor/node_modules/estree-walker/dist/estree-walker.umd.js +65 -0
  20. data/vendor/node_modules/estree-walker/package.json +33 -0
  21. data/vendor/node_modules/estree-walker/src/estree-walker.js +49 -0
  22. data/vendor/node_modules/expand-brackets/index.js +163 -0
  23. data/vendor/node_modules/expand-brackets/package.json +62 -0
  24. data/vendor/node_modules/expand-range/index.js +43 -0
  25. data/vendor/node_modules/expand-range/package.json +73 -0
  26. data/vendor/node_modules/extglob/index.js +178 -0
  27. data/vendor/node_modules/extglob/package.json +60 -0
  28. data/vendor/node_modules/filename-regex/index.js +10 -0
  29. data/vendor/node_modules/filename-regex/package.json +50 -0
  30. data/vendor/node_modules/fill-range/index.js +408 -0
  31. data/vendor/node_modules/fill-range/package.json +61 -0
  32. data/vendor/node_modules/for-in/index.js +16 -0
  33. data/vendor/node_modules/for-in/package.json +68 -0
  34. data/vendor/node_modules/for-own/index.js +19 -0
  35. data/vendor/node_modules/for-own/package.json +70 -0
  36. data/vendor/node_modules/glob-base/index.js +51 -0
  37. data/vendor/node_modules/glob-base/package.json +52 -0
  38. data/vendor/node_modules/glob-parent/index.js +10 -0
  39. data/vendor/node_modules/glob-parent/package.json +35 -0
  40. data/vendor/node_modules/glob-parent/test.js +28 -0
  41. data/vendor/node_modules/he/bin/he +148 -0
  42. data/vendor/node_modules/he/he.js +342 -0
  43. data/vendor/node_modules/he/man/he.1 +78 -0
  44. data/vendor/node_modules/he/package.json +56 -0
  45. data/vendor/node_modules/is-buffer/index.js +21 -0
  46. data/vendor/node_modules/is-buffer/package.json +51 -0
  47. data/vendor/node_modules/is-dotfile/index.js +14 -0
  48. data/vendor/node_modules/is-dotfile/package.json +69 -0
  49. data/vendor/node_modules/is-equal-shallow/index.js +27 -0
  50. data/vendor/node_modules/is-equal-shallow/package.json +54 -0
  51. data/vendor/node_modules/is-extendable/index.js +13 -0
  52. data/vendor/node_modules/is-extendable/package.json +51 -0
  53. data/vendor/node_modules/is-extglob/index.js +11 -0
  54. data/vendor/node_modules/is-extglob/package.json +48 -0
  55. data/vendor/node_modules/is-glob/index.js +14 -0
  56. data/vendor/node_modules/is-glob/package.json +60 -0
  57. data/vendor/node_modules/is-number/index.js +19 -0
  58. data/vendor/node_modules/is-number/package.json +59 -0
  59. data/vendor/node_modules/is-posix-bracket/index.js +10 -0
  60. data/vendor/node_modules/is-posix-bracket/package.json +64 -0
  61. data/vendor/node_modules/is-primitive/index.js +13 -0
  62. data/vendor/node_modules/is-primitive/package.json +46 -0
  63. data/vendor/node_modules/isarray/index.js +5 -0
  64. data/vendor/node_modules/isarray/package.json +45 -0
  65. data/vendor/node_modules/isarray/test.js +20 -0
  66. data/vendor/node_modules/isobject/index.js +14 -0
  67. data/vendor/node_modules/isobject/package.json +67 -0
  68. data/vendor/node_modules/kind-of/index.js +116 -0
  69. data/vendor/node_modules/kind-of/package.json +90 -0
  70. data/vendor/node_modules/magic-string/dist/magic-string.cjs.js +1287 -0
  71. data/vendor/node_modules/magic-string/dist/magic-string.es.js +1283 -0
  72. data/vendor/node_modules/magic-string/dist/magic-string.umd.js +1339 -0
  73. data/vendor/node_modules/magic-string/package.json +60 -0
  74. data/vendor/node_modules/magic-string/src/Bundle.js +263 -0
  75. data/vendor/node_modules/magic-string/src/Chunk.js +154 -0
  76. data/vendor/node_modules/magic-string/src/MagicString.js +618 -0
  77. data/vendor/node_modules/magic-string/src/index-legacy.js +6 -0
  78. data/vendor/node_modules/magic-string/src/index.js +4 -0
  79. data/vendor/node_modules/magic-string/src/utils/Mappings.js +117 -0
  80. data/vendor/node_modules/magic-string/src/utils/SourceMap.js +21 -0
  81. data/vendor/node_modules/magic-string/src/utils/Stats.js +18 -0
  82. data/vendor/node_modules/magic-string/src/utils/btoa.js +13 -0
  83. data/vendor/node_modules/magic-string/src/utils/getLocator.js +35 -0
  84. data/vendor/node_modules/magic-string/src/utils/getRelativePath.js +18 -0
  85. data/vendor/node_modules/magic-string/src/utils/guessIndent.js +25 -0
  86. data/vendor/node_modules/magic-string/src/utils/hasOwnProp.js +1 -0
  87. data/vendor/node_modules/magic-string/src/utils/isObject.js +5 -0
  88. data/vendor/node_modules/micromatch/index.js +431 -0
  89. data/vendor/node_modules/micromatch/lib/chars.js +67 -0
  90. data/vendor/node_modules/micromatch/lib/expand.js +304 -0
  91. data/vendor/node_modules/micromatch/lib/glob.js +193 -0
  92. data/vendor/node_modules/micromatch/lib/utils.js +149 -0
  93. data/vendor/node_modules/micromatch/package.json +114 -0
  94. data/vendor/node_modules/normalize-path/index.js +19 -0
  95. data/vendor/node_modules/normalize-path/package.json +78 -0
  96. data/vendor/node_modules/object.omit/index.js +40 -0
  97. data/vendor/node_modules/object.omit/package.json +67 -0
  98. data/vendor/node_modules/parse-glob/index.js +156 -0
  99. data/vendor/node_modules/parse-glob/package.json +62 -0
  100. data/vendor/node_modules/preserve/index.js +54 -0
  101. data/vendor/node_modules/preserve/package.json +48 -0
  102. data/vendor/node_modules/preserve/test.js +48 -0
  103. data/vendor/node_modules/randomatic/index.js +82 -0
  104. data/vendor/node_modules/randomatic/node_modules/is-number/index.js +22 -0
  105. data/vendor/node_modules/randomatic/node_modules/is-number/node_modules/kind-of/index.js +116 -0
  106. data/vendor/node_modules/randomatic/node_modules/is-number/node_modules/kind-of/package.json +90 -0
  107. data/vendor/node_modules/randomatic/node_modules/is-number/package.json +83 -0
  108. data/vendor/node_modules/randomatic/node_modules/kind-of/index.js +119 -0
  109. data/vendor/node_modules/randomatic/node_modules/kind-of/package.json +90 -0
  110. data/vendor/node_modules/randomatic/package.json +78 -0
  111. data/vendor/node_modules/regex-cache/index.js +68 -0
  112. data/vendor/node_modules/regex-cache/package.json +64 -0
  113. data/vendor/node_modules/remove-trailing-separator/index.js +17 -0
  114. data/vendor/node_modules/remove-trailing-separator/package.json +37 -0
  115. data/vendor/node_modules/repeat-element/index.js +18 -0
  116. data/vendor/node_modules/repeat-element/package.json +44 -0
  117. data/vendor/node_modules/repeat-string/index.js +70 -0
  118. data/vendor/node_modules/repeat-string/package.json +77 -0
  119. data/vendor/node_modules/rollup-plugin-vue2/dist/rollup-plugin-vue2.common.js +164 -0
  120. data/vendor/node_modules/rollup-plugin-vue2/dist/rollup-plugin-vue2.es.js +160 -0
  121. data/vendor/node_modules/rollup-plugin-vue2/package.json +50 -0
  122. data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.cjs.js +223 -0
  123. data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.es.js +214 -0
  124. data/vendor/node_modules/rollup-pluginutils/dist/pluginutils.es6.js +217 -0
  125. data/vendor/node_modules/rollup-pluginutils/package.json +40 -0
  126. data/vendor/node_modules/rollup-pluginutils/src/addExtension.js +6 -0
  127. data/vendor/node_modules/rollup-pluginutils/src/attachScopes.js +147 -0
  128. data/vendor/node_modules/rollup-pluginutils/src/createFilter.js +33 -0
  129. data/vendor/node_modules/rollup-pluginutils/src/index.js +4 -0
  130. data/vendor/node_modules/rollup-pluginutils/src/makeLegalIdentifier.js +15 -0
  131. data/vendor/node_modules/rollup-pluginutils/src/utils/ensureArray.js +5 -0
  132. data/vendor/node_modules/vlq/dist/vlq.js +91 -0
  133. data/vendor/node_modules/vlq/package.json +27 -0
  134. data/vendor/node_modules/vlq/src/vlq.js +78 -0
  135. data/vendor/node_modules/vue-template-compiler/browser.js +5237 -0
  136. data/vendor/node_modules/vue-template-compiler/build.js +4835 -0
  137. data/vendor/node_modules/vue-template-compiler/index.js +18 -0
  138. data/vendor/node_modules/vue-template-compiler/package.json +27 -0
  139. data/vendor/node_modules/vue-template-es2015-compiler/buble.js +14112 -0
  140. data/vendor/node_modules/vue-template-es2015-compiler/index.js +24 -0
  141. data/vendor/node_modules/vue-template-es2015-compiler/package.json +28 -0
  142. data/vendor/package.json +9 -0
  143. data/vendor/yarn.lock +268 -0
  144. metadata +242 -0
@@ -0,0 +1,618 @@
1
+ import Chunk from './Chunk.js';
2
+ import SourceMap from './utils/SourceMap.js';
3
+ import guessIndent from './utils/guessIndent.js';
4
+ import getRelativePath from './utils/getRelativePath.js';
5
+ import isObject from './utils/isObject.js';
6
+ import getLocator from './utils/getLocator.js';
7
+ import Mappings from './utils/Mappings.js';
8
+ import Stats from './utils/Stats.js';
9
+
10
+ const warned = {
11
+ insertLeft: false,
12
+ insertRight: false
13
+ };
14
+
15
+ export default function MagicString ( string, options = {} ) {
16
+ const chunk = new Chunk( 0, string.length, string );
17
+
18
+ Object.defineProperties( this, {
19
+ original: { writable: true, value: string },
20
+ outro: { writable: true, value: '' },
21
+ intro: { writable: true, value: '' },
22
+ firstChunk: { writable: true, value: chunk },
23
+ lastChunk: { writable: true, value: chunk },
24
+ lastSearchedChunk: { writable: true, value: chunk },
25
+ byStart: { writable: true, value: {} },
26
+ byEnd: { writable: true, value: {} },
27
+ filename: { writable: true, value: options.filename },
28
+ indentExclusionRanges: { writable: true, value: options.indentExclusionRanges },
29
+ sourcemapLocations: { writable: true, value: {} },
30
+ storedNames: { writable: true, value: {} },
31
+ indentStr: { writable: true, value: guessIndent( string ) }
32
+ });
33
+
34
+ if ( DEBUG ) {
35
+ Object.defineProperty( this, 'stats', { value: new Stats() });
36
+ }
37
+
38
+ this.byStart[ 0 ] = chunk;
39
+ this.byEnd[ string.length ] = chunk;
40
+ }
41
+
42
+ MagicString.prototype = {
43
+ addSourcemapLocation ( char ) {
44
+ this.sourcemapLocations[ char ] = true;
45
+ },
46
+
47
+ append ( content ) {
48
+ if ( typeof content !== 'string' ) throw new TypeError( 'outro content must be a string' );
49
+
50
+ this.outro += content;
51
+ return this;
52
+ },
53
+
54
+ appendLeft ( index, content ) {
55
+ if ( typeof content !== 'string' ) throw new TypeError( 'inserted content must be a string' );
56
+
57
+ if ( DEBUG ) this.stats.time( 'insertLeft' );
58
+
59
+ this._split( index );
60
+
61
+ const chunk = this.byEnd[ index ];
62
+
63
+ if ( chunk ) {
64
+ chunk.appendLeft( content );
65
+ } else {
66
+ this.intro += content;
67
+ }
68
+
69
+ if ( DEBUG ) this.stats.timeEnd( 'insertLeft' );
70
+ return this;
71
+ },
72
+
73
+ appendRight ( index, content ) {
74
+ if ( typeof content !== 'string' ) throw new TypeError( 'inserted content must be a string' );
75
+
76
+ if ( DEBUG ) this.stats.time( 'insertLeft' );
77
+
78
+ this._split( index );
79
+
80
+ const chunk = this.byStart[ index ];
81
+
82
+ if ( chunk ) {
83
+ chunk.appendRight( content );
84
+ } else {
85
+ this.outro += content;
86
+ }
87
+
88
+ if ( DEBUG ) this.stats.timeEnd( 'insertLeft' );
89
+ return this;
90
+ },
91
+
92
+ clone () {
93
+ const cloned = new MagicString( this.original, { filename: this.filename });
94
+
95
+ let originalChunk = this.firstChunk;
96
+ let clonedChunk = cloned.firstChunk = cloned.lastSearchedChunk = originalChunk.clone();
97
+
98
+ while ( originalChunk ) {
99
+ cloned.byStart[ clonedChunk.start ] = clonedChunk;
100
+ cloned.byEnd[ clonedChunk.end ] = clonedChunk;
101
+
102
+ const nextOriginalChunk = originalChunk.next;
103
+ const nextClonedChunk = nextOriginalChunk && nextOriginalChunk.clone();
104
+
105
+ if ( nextClonedChunk ) {
106
+ clonedChunk.next = nextClonedChunk;
107
+ nextClonedChunk.previous = clonedChunk;
108
+
109
+ clonedChunk = nextClonedChunk;
110
+ }
111
+
112
+ originalChunk = nextOriginalChunk;
113
+ }
114
+
115
+ cloned.lastChunk = clonedChunk;
116
+
117
+ if ( this.indentExclusionRanges ) {
118
+ cloned.indentExclusionRanges = typeof this.indentExclusionRanges[0] === 'number' ?
119
+ [ this.indentExclusionRanges[0], this.indentExclusionRanges[1] ] :
120
+ this.indentExclusionRanges.map( range => [ range.start, range.end ] );
121
+ }
122
+
123
+ Object.keys( this.sourcemapLocations ).forEach( loc => {
124
+ cloned.sourcemapLocations[ loc ] = true;
125
+ });
126
+
127
+ return cloned;
128
+ },
129
+
130
+ generateMap ( options ) {
131
+ options = options || {};
132
+
133
+ const sourceIndex = 0;
134
+ const names = Object.keys( this.storedNames );
135
+ const mappings = new Mappings( options.hires );
136
+
137
+ const locate = getLocator( this.original );
138
+
139
+ if ( this.intro ) {
140
+ mappings.advance( this.intro );
141
+ }
142
+
143
+ this.firstChunk.eachNext( chunk => {
144
+ const loc = locate( chunk.start );
145
+
146
+ if ( chunk.intro.length ) mappings.advance( chunk.intro );
147
+
148
+ if ( chunk.edited ) {
149
+ mappings.addEdit( sourceIndex, chunk.content, chunk.original, loc, chunk.storeName ? names.indexOf( chunk.original ) : -1 );
150
+ } else {
151
+ mappings.addUneditedChunk( sourceIndex, chunk, this.original, loc, this.sourcemapLocations );
152
+ }
153
+
154
+ if ( chunk.outro.length ) mappings.advance( chunk.outro );
155
+ });
156
+
157
+ if ( DEBUG ) this.stats.time( 'generateMap' );
158
+ const map = new SourceMap({
159
+ file: ( options.file ? options.file.split( /[\/\\]/ ).pop() : null ),
160
+ sources: [ options.source ? getRelativePath( options.file || '', options.source ) : null ],
161
+ sourcesContent: options.includeContent ? [ this.original ] : [ null ],
162
+ names,
163
+ mappings: mappings.encode()
164
+ });
165
+ if ( DEBUG ) this.stats.timeEnd( 'generateMap' );
166
+
167
+ return map;
168
+ },
169
+
170
+ getIndentString () {
171
+ return this.indentStr === null ? '\t' : this.indentStr;
172
+ },
173
+
174
+ indent ( indentStr, options ) {
175
+ const pattern = /^[^\r\n]/gm;
176
+
177
+ if ( isObject( indentStr ) ) {
178
+ options = indentStr;
179
+ indentStr = undefined;
180
+ }
181
+
182
+ indentStr = indentStr !== undefined ? indentStr : ( this.indentStr || '\t' );
183
+
184
+ if ( indentStr === '' ) return this; // noop
185
+
186
+ options = options || {};
187
+
188
+ // Process exclusion ranges
189
+ const isExcluded = {};
190
+
191
+ if ( options.exclude ) {
192
+ const exclusions = typeof options.exclude[0] === 'number' ? [ options.exclude ] : options.exclude;
193
+ exclusions.forEach( exclusion => {
194
+ for ( let i = exclusion[0]; i < exclusion[1]; i += 1 ) {
195
+ isExcluded[i] = true;
196
+ }
197
+ });
198
+ }
199
+
200
+ let shouldIndentNextCharacter = options.indentStart !== false;
201
+ const replacer = match => {
202
+ if ( shouldIndentNextCharacter ) return `${indentStr}${match}`;
203
+ shouldIndentNextCharacter = true;
204
+ return match;
205
+ };
206
+
207
+ this.intro = this.intro.replace( pattern, replacer );
208
+
209
+ let charIndex = 0;
210
+
211
+ let chunk = this.firstChunk;
212
+
213
+ while ( chunk ) {
214
+ const end = chunk.end;
215
+
216
+ if ( chunk.edited ) {
217
+ if ( !isExcluded[ charIndex ] ) {
218
+ chunk.content = chunk.content.replace( pattern, replacer );
219
+
220
+ if ( chunk.content.length ) {
221
+ shouldIndentNextCharacter = chunk.content[ chunk.content.length - 1 ] === '\n';
222
+ }
223
+ }
224
+ } else {
225
+ charIndex = chunk.start;
226
+
227
+ while ( charIndex < end ) {
228
+ if ( !isExcluded[ charIndex ] ) {
229
+ const char = this.original[ charIndex ];
230
+
231
+ if ( char === '\n' ) {
232
+ shouldIndentNextCharacter = true;
233
+ } else if ( char !== '\r' && shouldIndentNextCharacter ) {
234
+ shouldIndentNextCharacter = false;
235
+
236
+ if ( charIndex === chunk.start ) {
237
+ chunk.prependRight( indentStr );
238
+ } else {
239
+ const rhs = chunk.split( charIndex );
240
+ rhs.prependRight( indentStr );
241
+
242
+ this.byStart[ charIndex ] = rhs;
243
+ this.byEnd[ charIndex ] = chunk;
244
+
245
+ chunk = rhs;
246
+ }
247
+ }
248
+ }
249
+
250
+ charIndex += 1;
251
+ }
252
+ }
253
+
254
+ charIndex = chunk.end;
255
+ chunk = chunk.next;
256
+ }
257
+
258
+ this.outro = this.outro.replace( pattern, replacer );
259
+
260
+ return this;
261
+ },
262
+
263
+ insert () {
264
+ throw new Error( 'magicString.insert(...) is deprecated. Use insertRight(...) or insertLeft(...)' );
265
+ },
266
+
267
+ insertLeft ( index, content ) {
268
+ if ( !warned.insertLeft ) {
269
+ console.warn( 'magicString.insertLeft(...) is deprecated. Use magicString.appendLeft(...) instead' ); // eslint-disable-line no-console
270
+ warned.insertLeft = true;
271
+ }
272
+
273
+ return this.appendLeft( index, content );
274
+ },
275
+
276
+ insertRight ( index, content ) {
277
+ if ( !warned.insertRight ) {
278
+ console.warn( 'magicString.insertRight(...) is deprecated. Use magicString.prependRight(...) instead' ); // eslint-disable-line no-console
279
+ warned.insertRight = true;
280
+ }
281
+
282
+ return this.prependRight( index, content );
283
+ },
284
+
285
+ move ( start, end, index ) {
286
+ if ( index >= start && index <= end ) throw new Error( 'Cannot move a selection inside itself' );
287
+
288
+ if ( DEBUG ) this.stats.time( 'move' );
289
+
290
+ this._split( start );
291
+ this._split( end );
292
+ this._split( index );
293
+
294
+ const first = this.byStart[ start ];
295
+ const last = this.byEnd[ end ];
296
+
297
+ const oldLeft = first.previous;
298
+ const oldRight = last.next;
299
+
300
+ const newRight = this.byStart[ index ];
301
+ if ( !newRight && last === this.lastChunk ) return this;
302
+ const newLeft = newRight ? newRight.previous : this.lastChunk;
303
+
304
+ if ( oldLeft ) oldLeft.next = oldRight;
305
+ if ( oldRight ) oldRight.previous = oldLeft;
306
+
307
+ if ( newLeft ) newLeft.next = first;
308
+ if ( newRight ) newRight.previous = last;
309
+
310
+ if ( !first.previous ) this.firstChunk = last.next;
311
+ if ( !last.next ) {
312
+ this.lastChunk = first.previous;
313
+ this.lastChunk.next = null;
314
+ }
315
+
316
+ first.previous = newLeft;
317
+ last.next = newRight;
318
+
319
+ if ( !newLeft ) this.firstChunk = first;
320
+ if ( !newRight ) this.lastChunk = last;
321
+
322
+ if ( DEBUG ) this.stats.timeEnd( 'move' );
323
+ return this;
324
+ },
325
+
326
+ overwrite ( start, end, content, storeName ) {
327
+ if ( typeof content !== 'string' ) throw new TypeError( 'replacement content must be a string' );
328
+
329
+ while ( start < 0 ) start += this.original.length;
330
+ while ( end < 0 ) end += this.original.length;
331
+
332
+ if ( end > this.original.length ) throw new Error( 'end is out of bounds' );
333
+ if ( start === end ) throw new Error( 'Cannot overwrite a zero-length range – use insertLeft or insertRight instead' );
334
+
335
+ if ( DEBUG ) this.stats.time( 'overwrite' );
336
+
337
+ this._split( start );
338
+ this._split( end );
339
+
340
+ if ( storeName ) {
341
+ const original = this.original.slice( start, end );
342
+ this.storedNames[ original ] = true;
343
+ }
344
+
345
+ const first = this.byStart[ start ];
346
+ const last = this.byEnd[ end ];
347
+
348
+ if ( first ) {
349
+ if ( end > first.end && first.next !== this.byStart[ first.end ] ) {
350
+ throw new Error( 'Cannot overwrite across a split point' );
351
+ }
352
+
353
+ first.edit( content, storeName );
354
+
355
+ if ( last ) {
356
+ first.next = last.next;
357
+ } else {
358
+ first.next = null;
359
+ this.lastChunk = first;
360
+ }
361
+
362
+ first.original = this.original.slice( start, end );
363
+ first.end = end;
364
+ }
365
+
366
+ else {
367
+ // must be inserting at the end
368
+ const newChunk = new Chunk( start, end, '' ).edit( content, storeName );
369
+
370
+ // TODO last chunk in the array may not be the last chunk, if it's moved...
371
+ last.next = newChunk;
372
+ newChunk.previous = last;
373
+ }
374
+
375
+ if ( DEBUG ) this.stats.timeEnd( 'overwrite' );
376
+ return this;
377
+ },
378
+
379
+ prepend ( content ) {
380
+ if ( typeof content !== 'string' ) throw new TypeError( 'outro content must be a string' );
381
+
382
+ this.intro = content + this.intro;
383
+ return this;
384
+ },
385
+
386
+ prependLeft ( index, content ) {
387
+ if ( typeof content !== 'string' ) throw new TypeError( 'inserted content must be a string' );
388
+
389
+ if ( DEBUG ) this.stats.time( 'insertRight' );
390
+
391
+ this._split( index );
392
+
393
+ const chunk = this.byEnd[ index ];
394
+
395
+ if ( chunk ) {
396
+ chunk.prependLeft( content );
397
+ } else {
398
+ this.intro = content + this.intro;
399
+ }
400
+
401
+ if ( DEBUG ) this.stats.timeEnd( 'insertRight' );
402
+ return this;
403
+ },
404
+
405
+ prependRight ( index, content ) {
406
+ if ( typeof content !== 'string' ) throw new TypeError( 'inserted content must be a string' );
407
+
408
+ if ( DEBUG ) this.stats.time( 'insertRight' );
409
+
410
+ this._split( index );
411
+
412
+ const chunk = this.byStart[ index ];
413
+
414
+ if ( chunk ) {
415
+ chunk.prependRight( content );
416
+ } else {
417
+ this.outro = content + this.outro;
418
+ }
419
+
420
+ if ( DEBUG ) this.stats.timeEnd( 'insertRight' );
421
+ return this;
422
+ },
423
+
424
+ remove ( start, end ) {
425
+ while ( start < 0 ) start += this.original.length;
426
+ while ( end < 0 ) end += this.original.length;
427
+
428
+ if ( start === end ) return this;
429
+
430
+ if ( start < 0 || end > this.original.length ) throw new Error( 'Character is out of bounds' );
431
+ if ( start > end ) throw new Error( 'end must be greater than start' );
432
+
433
+ if ( DEBUG ) this.stats.time( 'remove' );
434
+
435
+ this._split( start );
436
+ this._split( end );
437
+
438
+ let chunk = this.byStart[ start ];
439
+
440
+ while ( chunk ) {
441
+ chunk.intro = '';
442
+ chunk.outro = '';
443
+ chunk.edit( '' );
444
+
445
+ chunk = end > chunk.end ? this.byStart[ chunk.end ] : null;
446
+ }
447
+
448
+ if ( DEBUG ) this.stats.timeEnd( 'remove' );
449
+ return this;
450
+ },
451
+
452
+ slice ( start = 0, end = this.original.length ) {
453
+ while ( start < 0 ) start += this.original.length;
454
+ while ( end < 0 ) end += this.original.length;
455
+
456
+ let result = '';
457
+
458
+ // find start chunk
459
+ let chunk = this.firstChunk;
460
+ while ( chunk && ( chunk.start > start || chunk.end <= start ) ) {
461
+
462
+ // found end chunk before start
463
+ if ( chunk.start < end && chunk.end >= end ) {
464
+ return result;
465
+ }
466
+
467
+ chunk = chunk.next;
468
+ }
469
+
470
+ if ( chunk && chunk.edited && chunk.start !== start ) throw new Error(`Cannot use replaced character ${start} as slice start anchor.`);
471
+
472
+ const startChunk = chunk;
473
+ while ( chunk ) {
474
+ if ( chunk.intro && ( startChunk !== chunk || chunk.start === start ) ) {
475
+ result += chunk.intro;
476
+ }
477
+
478
+ const containsEnd = chunk.start < end && chunk.end >= end;
479
+ if ( containsEnd && chunk.edited && chunk.end !== end ) throw new Error(`Cannot use replaced character ${end} as slice end anchor.`);
480
+
481
+ const sliceStart = startChunk === chunk ? start - chunk.start : 0;
482
+ const sliceEnd = containsEnd ? chunk.content.length + end - chunk.end : chunk.content.length;
483
+
484
+ result += chunk.content.slice( sliceStart, sliceEnd );
485
+
486
+ if ( chunk.outro && ( !containsEnd || chunk.end === end ) ) {
487
+ result += chunk.outro;
488
+ }
489
+
490
+ if ( containsEnd ) {
491
+ break;
492
+ }
493
+
494
+ chunk = chunk.next;
495
+ }
496
+
497
+ return result;
498
+ },
499
+
500
+ // TODO deprecate this? not really very useful
501
+ snip ( start, end ) {
502
+ const clone = this.clone();
503
+ clone.remove( 0, start );
504
+ clone.remove( end, clone.original.length );
505
+
506
+ return clone;
507
+ },
508
+
509
+ _split ( index ) {
510
+ if ( this.byStart[ index ] || this.byEnd[ index ] ) return;
511
+
512
+ if ( DEBUG ) this.stats.time( '_split' );
513
+
514
+ let chunk = this.lastSearchedChunk;
515
+ const searchForward = index > chunk.end;
516
+
517
+ while ( true ) {
518
+ if ( chunk.contains( index ) ) return this._splitChunk( chunk, index );
519
+
520
+ chunk = searchForward ?
521
+ this.byStart[ chunk.end ] :
522
+ this.byEnd[ chunk.start ];
523
+ }
524
+ },
525
+
526
+ _splitChunk ( chunk, index ) {
527
+ if ( chunk.edited && chunk.content.length ) { // zero-length edited chunks are a special case (overlapping replacements)
528
+ const loc = getLocator( this.original )( index );
529
+ throw new Error( `Cannot split a chunk that has already been edited (${loc.line}:${loc.column} – "${chunk.original}")` );
530
+ }
531
+
532
+ const newChunk = chunk.split( index );
533
+
534
+ this.byEnd[ index ] = chunk;
535
+ this.byStart[ index ] = newChunk;
536
+ this.byEnd[ newChunk.end ] = newChunk;
537
+
538
+ if ( chunk === this.lastChunk ) this.lastChunk = newChunk;
539
+
540
+ this.lastSearchedChunk = chunk;
541
+ if ( DEBUG ) this.stats.timeEnd( '_split' );
542
+ return true;
543
+ },
544
+
545
+ toString () {
546
+ let str = this.intro;
547
+
548
+ let chunk = this.firstChunk;
549
+ while ( chunk ) {
550
+ str += chunk.toString();
551
+ chunk = chunk.next;
552
+ }
553
+
554
+ return str + this.outro;
555
+ },
556
+
557
+ trimLines () {
558
+ return this.trim('[\\r\\n]');
559
+ },
560
+
561
+ trim ( charType ) {
562
+ return this.trimStart( charType ).trimEnd( charType );
563
+ },
564
+
565
+ trimEnd ( charType ) {
566
+ const rx = new RegExp( ( charType || '\\s' ) + '+$' );
567
+
568
+ this.outro = this.outro.replace( rx, '' );
569
+ if ( this.outro.length ) return this;
570
+
571
+ let chunk = this.lastChunk;
572
+
573
+ do {
574
+ const end = chunk.end;
575
+ const aborted = chunk.trimEnd( rx );
576
+
577
+ // if chunk was trimmed, we have a new lastChunk
578
+ if ( chunk.end !== end ) {
579
+ this.lastChunk = chunk.next;
580
+
581
+ this.byEnd[ chunk.end ] = chunk;
582
+ this.byStart[ chunk.next.start ] = chunk.next;
583
+ }
584
+
585
+ if ( aborted ) return this;
586
+ chunk = chunk.previous;
587
+ } while ( chunk );
588
+
589
+ return this;
590
+ },
591
+
592
+ trimStart ( charType ) {
593
+ const rx = new RegExp( '^' + ( charType || '\\s' ) + '+' );
594
+
595
+ this.intro = this.intro.replace( rx, '' );
596
+ if ( this.intro.length ) return this;
597
+
598
+ let chunk = this.firstChunk;
599
+
600
+ do {
601
+ const end = chunk.end;
602
+ const aborted = chunk.trimStart( rx );
603
+
604
+ if ( chunk.end !== end ) {
605
+ // special case...
606
+ if ( chunk === this.lastChunk ) this.lastChunk = chunk.next;
607
+
608
+ this.byEnd[ chunk.end ] = chunk;
609
+ this.byStart[ chunk.next.start ] = chunk.next;
610
+ }
611
+
612
+ if ( aborted ) return this;
613
+ chunk = chunk.next;
614
+ } while ( chunk );
615
+
616
+ return this;
617
+ }
618
+ };