magic-string

repository·master·Indexed 25 days ago

https://github.com/rich-harris/magic-string

A small, fast utility for manipulating strings and generating version 3 sourcemaps. It allows for light modifications—such as replacing characters, wrapping code, or adding headers and footers—while maintaining character indices relative to the original string. It includes a Bundle class for concatenating multiple MagicString instances into a single output with a combined sourcemap.

Tokens
4.1K
Snippets
12
Records
32
Agent score
83%

What's inside magic-string

  1. Basic usage of magic-string

    master

    magic-string allows you to perform light modifications to a string (like replacing characters, wrapping content, or prepending/appending) while maintaining the ability to generate source maps. Character indices always refer to the original string.

    Most methods are chainable.

    import MagicString from 'magic-string'
    
    const s = new MagicString('problems = 99')
    
    s.update(0, 8, 'answer')
    s.toString() // 'answer = 99'
    
    s.update(11, 13, '42') // character indices always refer to the original string
    s.toString() // 'answer = 42'
    
    s.prepend('var ').append(';') // most methods are chainable
    s.toString() // 'var answer = 42;'
    
    const map = s.generateMap({
      source: 'source.js',
      file: 'converted.js.map',
      includeContent: true,
    }) // generates a v3 sourcemap
  2. Add a MagicString instance directly to a Bundle

    master

    If you have already configured a MagicString instance with a filename or indentExclusionRanges during its construction, you can pass the instance directly to bundle.addSource() instead of using an object wrapper.

    const bundle = new Bundle()
    const source = new MagicString(someCode, {
      filename: 'foo.js',
    })
    
    bundle.addSource(source)
  3. Bundle multiple sources with Bundle

    master

    Use the Bundle class to concatenate several MagicString instances into a single output. You can add sources by providing an object containing filename, content, and optional properties like ignoreList or indentExclusionRanges.

    • filename: The name of the source file.
    • content: A MagicString instance.
    • ignoreList: A boolean hint for debuggers (set to false to ensure the source is not ignored).
    • indentExclusionRanges: Passed to s.indent() to define specific ranges that should not be indented.

    After adding sources, you can use methods like .indent(), .prepend(), and .append() on the bundle itself. To get the final string, use .toString(). To generate a source map for the entire bundle, use .generateMap() with options similar to s.generateMap().

    import MagicString, { Bundle } from 'magic-string'
    
    const bundle = new Bundle()
    
    bundle.addSource({
      filename: 'foo.js',
      content: new MagicString('var answer = 42;'),
    })
    
    bundle.addSource({
      filename: 'bar.js',
      content: new MagicString('console.log( answer )'),
    })
    
    // Sources can be marked as ignore-listed
    bundle.addSource({
      filename: 'some-3rdparty-library.js',
      content: new MagicString('function myLib(){}'),
      ignoreList: false,
    })
    
    bundle
      .indent()
      .prepend('(function () {
    ')
      .append('}());')
    
    const output = bundle.toString()
    // (function () {
    //   var answer = 42;
    //   console.log( answer );
    // }());
    
    const map = bundle.generateMap({
      file: 'bundle.js',
      includeContent: true,
      hires: true,
    })
  4. Manipulate string structure with s.append(), s.prepend(), and s.move()

    master

    Use these methods to change the structure of the generated string:

    • s.append(content): Appends content to the end.
    • s.prepend(content): Prepends content to the start.
    • s.appendLeft(index, content): Appends content at index in the original string. If a range ending with index is moved, the insert moves with it.
    • s.appendRight(index, content): Appends content at index in the original string. If a range starting with index is moved, the insert moves with it.
    • s.prependLeft(index, content): Same as appendLeft, but inserted before previous appends/prepends at index.
    • s.prependRight(index, content): Same as appendRight, but inserted before previous appends/prepends at index.
    • s.move(start, end, index): Moves characters from start to end to index in the original string.
  5. Replace text with s.replace() and s.replaceAll()

    master

    Perform string replacements using RegExp or strings. Unlike String.prototype.replace, these methods always match against the original string and mutate the MagicString state.

    • s.replace(regexpOrString, substitution): Replaces the first match.
    • s.replaceAll(regexpOrString, substitution): Replaces all matches. If using a RegExp, it must have the global (g) flag set, otherwise a TypeError is thrown.

    The substitution parameter supports strings and functions.

    import MagicString from 'magic-string'
    
    const s = new MagicString(source)
    
    s.replace('foo', 'bar')
    s.replace('foo', (str, index, s) => `${str}-${index}`)
    s.replace(/foo/g, 'bar')
    s.replace(/(\w)(\d+)/g, (_, $1, $2) => $1.toUpperCase() + $2)
    
    s.replaceAll('foo', 'bar')
  6. Generate a version 3 sourcemap with s.generateMap()

    master

    Generates a version 3 sourcemap. The returned sourcemap object includes two convenience methods:

    • toString(): Returns the equivalent of JSON.stringify(map).
    • toUrl(): Returns a DataURI containing the sourcemap, useful for appending //# sourceMappingURL= to your code.

    Options:

    • file: The filename where you plan to write the sourcemap.
    • source: The filename of the file containing the original source.
    • includeContent: Whether to include the original content in the map's sourcesContent array.
    • hires: Whether the mapping should be high-resolution (maps every character) or low-resolution (maps line/word boundaries). Use "boundary" for semi-hi-res mappings segmented per word boundary.
  7. Initialize MagicString with options

    master

    When creating a new MagicString instance, you can pass an options object to configure behavior for subsequent operations or bundling.

    Options:

    • filename: The filename of the source.
    • indentExclusionRanges: An array of [start, end] character ranges to exclude from indentation.
    • ignoreList: Boolean to mark source as ignore in DevTools.
    • offset: An integer to adjust the incoming position for various APIs (like slice, update, remove, etc.).
    const s = new MagicString(someCode, {
      filename: 'foo.js',
      indentExclusionRanges: [
        /* ... */
      ],
      ignoreList: false,
      offset: 0,
    })
  8. Update and Overwrite content with s.update() and s.overwrite()

    master

    Both methods allow replacing a range of the original string with new content.

    • s.update(start, end, content, [options]): Replaces characters from start to end. The options object can include:
      • storeName: If true, the original name is stored for the sourcemap names array.
      • overwrite: Defaults to false. If true, it overwrites appended/prepended content in that range. (Note: s.update is equivalent to s.overwrite with contentOnly: true).
    • s.overwrite(start, end, content, [options]): Similar to update, but allows controlling whether appended/prepended content is overwritten via the contentOnly property.

    Note: Use s.update if you wish to avoid overwriting the appended/prepended content.

  9. Configure Bundle options

    master

    When instantiating a Bundle, you can provide an optional BundleOptions object to set the initial intro and separator used when joining sources.

    • intro (string): Content to prepend to the beginning of the bundle.
    • separator (string): The string used to separate sources. Defaults to \n if not specified.
  10. Configure SourceMap generation options

    master

    When generating a sourcemap, you can provide a SourceMapOptions object to control the resolution, file metadata, and content inclusion.

    • hires: Controls mapping resolution.
      • true: High-resolution (maps every character; precise but larger).
      • false: Low-resolution (maps lines; faster and smaller).
      • 'boundary': Semi-high-resolution (segments per word boundary).
    • file: The filename where the sourcemap will be written.
    • source: The filename of the original source file.
    • includeContent: Whether to include the original source code in the sourcesContent array.