UNPKG

9.35 kBMarkdownView Raw
1# magic-string
2
3<p align="center">
4 <a href="https://travis-ci.org/Rich-Harris/magic-string">
5 <img src="http://img.shields.io/travis/Rich-Harris/magic-string.svg"
6 alt="build status">
7 </a>
8 <a href="https://npmjs.org/package/magic-string">
9 <img src="https://img.shields.io/npm/v/magic-string.svg"
10 alt="npm version">
11 </a>
12 <a href="https://github.com/Rich-Harris/magic-string/blob/master/LICENSE.md">
13 <img src="https://img.shields.io/npm/l/magic-string.svg"
14 alt="license">
15 </a>
16 <a href="https://david-dm.org/Rich-Harris/magic-string">
17 <img src="https://david-dm.org/Rich-Harris/magic-string.svg"
18 alt="dependency status">
19 </a>
20 <a href="http://codecov.io/github/Rich-Harris/magic-string?branch=master">
21 <img src="http://codecov.io/github/Rich-Harris/magic-string/coverage.svg?branch=master" alt="Coverage via Codecov" />
22 </a>
23</p>
24
25Suppose you have some source code. You want to make some light modifications to it - replacing a few characters here and there, wrapping it with a header and footer, etc - and ideally you'd like to generate a source map at the end of it. You've thought about using something like [recast](https://github.com/benjamn/recast) (which allows you to generate an AST from some JavaScript, manipulate it, and reprint it with a sourcemap without losing your comments and formatting), but it seems like overkill for your needs (or maybe the source code isn't JavaScript).
26
27Your requirements are, frankly, rather niche. But they're requirements that I also have, and for which I made magic-string. It's a small, fast utility for manipulating strings and generating sourcemaps.
28
29## Installation
30
31magic-string works in both node.js and browser environments. For node, install with npm:
32
33```bash
34npm i magic-string
35```
36
37To use in browser, grab the [magic-string.umd.js](https://unpkg.com/magic-string/dist/magic-string.umd.js) file and add it to your page:
38
39```html
40<script src='magic-string.umd.js'></script>
41```
42
43(It also works with various module systems, if you prefer that sort of thing - it has a dependency on [vlq](https://github.com/Rich-Harris/vlq).)
44
45## Usage
46
47These examples assume you're in node.js, or something similar:
48
49```js
50var MagicString = require( 'magic-string' );
51var s = new MagicString( 'problems = 99' );
52
53s.overwrite( 0, 8, 'answer' );
54s.toString(); // 'answer = 99'
55
56s.overwrite( 11, 13, '42' ); // character indices always refer to the original string
57s.toString(); // 'answer = 42'
58
59s.prepend( 'var ' ).append( ';' ); // most methods are chainable
60s.toString(); // 'var answer = 42;'
61
62var map = s.generateMap({
63 source: 'source.js',
64 file: 'converted.js.map',
65 includeContent: true
66}); // generates a v3 sourcemap
67
68require( 'fs' ).writeFile( 'converted.js', s.toString() );
69require( 'fs' ).writeFile( 'converted.js.map', map.toString() );
70```
71
72You can pass an options argument:
73
74```js
75var s = new MagicString( someCode, {
76 // both these options will be used if you later
77 // call `bundle.addSource( s )` - see below
78 filename: 'foo.js',
79 indentExclusionRanges: [/*...*/]
80});
81```
82
83## Methods
84
85### s.addSourcemapLocation( index )
86
87Adds the specified character index (with respect to the original string) to sourcemap mappings, if `hires` is `false` (see below).
88
89### s.append( content )
90
91Appends the specified content to the end of the string. Returns `this`.
92
93### s.appendLeft( index, content )
94
95Appends the specified `content` at the `index` in the original string. If a range *ending* with `index` is subsequently moved, the insert will be moved with it. Returns `this`. See also `s.prependLeft(...)`.
96
97### s.appendRight( index, content )
98
99Appends the specified `content` at the `index` in the original string. If a range *starting* with `index` is subsequently moved, the insert will be moved with it. Returns `this`. See also `s.prependRight(...)`.
100
101### s.clone()
102
103Does what you'd expect.
104
105### s.generateMap( options )
106
107Generates a [version 3 sourcemap](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit). All options are, well, optional:
108
109* `file` - the filename where you plan to write the sourcemap
110* `source` - the filename of the file containing the original source
111* `includeContent` - whether to include the original content in the map's `sourcesContent` array
112* `hires` - whether the mapping should be high-resolution. Hi-res mappings map every single character, meaning (for example) your devtools will always be able to pinpoint the exact location of function calls and so on. With lo-res mappings, devtools may only be able to identify the correct line - but they're quicker to generate and less bulky. If sourcemap locations have been specified with `s.addSourceMapLocation()`, they will be used here.
113
114The returned sourcemap has two (non-enumerable) methods attached for convenience:
115
116* `toString` - returns the equivalent of `JSON.stringify(map)`
117* `toUrl` - returns a DataURI containing the sourcemap. Useful for doing this sort of thing:
118
119```js
120code += '\n//# sourceMappingURL=' + map.toUrl();
121```
122
123### s.indent( prefix[, options] )
124
125Prefixes each line of the string with `prefix`. If `prefix` is not supplied, the indentation will be guessed from the original content, falling back to a single tab character. Returns `this`.
126
127The `options` argument can have an `exclude` property, which is an array of `[start, end]` character ranges. These ranges will be excluded from the indentation - useful for (e.g.) multiline strings.
128
129### s.insertLeft( index, content )
130
131**DEPRECATED** since 0.17 – use `s.appendLeft(...)` instead
132
133### s.insertRight( index, content )
134
135**DEPRECATED** since 0.17 – use `s.prependRight(...)` instead
136
137### s.locate( index )
138
139**DEPRECATED** since 0.10 – see [#30](https://github.com/Rich-Harris/magic-string/pull/30)
140
141### s.locateOrigin( index )
142
143**DEPRECATED** since 0.10 – see [#30](https://github.com/Rich-Harris/magic-string/pull/30)
144
145### s.move( start, end, newIndex )
146
147Moves the characters from `start` and `end` to `index`. Returns `this`.
148
149### s.overwrite( start, end, content[, options] )
150
151Replaces the characters from `start` to `end` with `content`. The same restrictions as `s.remove()` apply. Returns `this`.
152
153The fourth argument is optional. It can have a `storeName` property — if `true`, the original name will be stored for later inclusion in a sourcemap's `names` array — and a `contentOnly` property which determines whether only the content is overwritten, or anything that was appended/prepended to the range as well.
154
155### s.prepend( content )
156
157Prepends the string with the specified content. Returns `this`.
158
159### s.prependLeft ( index, content )
160
161Same as `s.appendLeft(...)`, except that the inserted content will go *before* any previous appends or prepends at `index`
162
163### s.prependRight ( index, content )
164
165Same as `s.appendRight(...)`, except that the inserted content will go *before* any previous appends or prepends at `index`
166
167### s.remove( start, end )
168
169Removes the characters from `start` to `end` (of the original string, **not** the generated string). Removing the same content twice, or making removals that partially overlap, will cause an error. Returns `this`.
170
171### s.slice( start, end )
172
173Returns the content of the generated string that corresponds to the slice between `start` and `end` of the original string. Throws error if the indices are for characters that were already removed.
174
175### s.snip( start, end )
176
177Returns a clone of `s`, with all content before the `start` and `end` characters of the original string removed.
178
179### s.toString()
180
181Returns the generated string.
182
183### s.trim([ charType ])
184
185Trims content matching `charType` (defaults to `\s`, i.e. whitespace) from the start and end. Returns `this`.
186
187### s.trimStart([ charType ])
188
189Trims content matching `charType` (defaults to `\s`, i.e. whitespace) from the start. Returns `this`.
190
191### s.trimEnd([ charType ])
192
193Trims content matching `charType` (defaults to `\s`, i.e. whitespace) from the end. Returns `this`.
194
195### s.trimLines()
196
197Removes empty lines from the start and end. Returns `this`.
198
199## Bundling
200
201To concatenate several sources, use `MagicString.Bundle`:
202
203```js
204var bundle = new MagicString.Bundle();
205
206bundle.addSource({
207 filename: 'foo.js',
208 content: new MagicString( 'var answer = 42;' )
209});
210
211bundle.addSource({
212 filename: 'bar.js',
213 content: new MagicString( 'console.log( answer )' )
214});
215
216// Advanced: a source can include an `indentExclusionRanges` property
217// alongside `filename` and `content`. This will be passed to `s.indent()`
218// - see documentation above
219
220bundle.indent() // optionally, pass an indent string, otherwise it will be guessed
221 .prepend( '(function () {\n' )
222 .append( '}());' );
223
224bundle.toString();
225// (function () {
226// var answer = 42;
227// console.log( answer );
228// }());
229
230// options are as per `s.generateMap()` above
231var map = bundle.generateMap({
232 file: 'bundle.js',
233 includeContent: true,
234 hires: true
235});
236```
237
238As an alternative syntax, if you a) don't have `filename` or `indentExclusionRanges` options, or b) passed those in when you used `new MagicString(...)`, you can simply pass the `MagicString` instance itself:
239
240```js
241var bundle = new MagicString.Bundle();
242var source = new MagicString( someCode, {
243 filename: 'foo.js'
244});
245
246bundle.addSource( source );
247```
248
249## License
250
251MIT