Skip to content

Instantly share code, notes, and snippets.

@dmail
Created March 1, 2022 14:29
Show Gist options
  • Save dmail/62c674c7306e1607bae214e0f4aab68c to your computer and use it in GitHub Desktop.
Save dmail/62c674c7306e1607bae214e0f4aab68c to your computer and use it in GitHub Desktop.
Magic source
import { urlToFileSystemPath } from "@jsenv/filesystem"
import { require } from "@jsenv/core/src/internal/require.js"
export const createMagicSource = ({ url, content, sourcemap }) => {
if (content === undefined) {
throw new Error("content missing")
}
const filename = urlToFileSystemPath(url)
const {
OriginalSource,
SourceMapSource,
ConcatSource,
ReplaceSource,
} = require("webpack-sources")
let firstSource
if (sourcemap) {
firstSource = new SourceMapSource(content, filename, sourcemap)
} else {
firstSource = new OriginalSource(content, filename)
}
const mutations = []
return {
prepend: (string) => {
mutations.push((source) => {
const concatSource = new ConcatSource(string, source)
return concatSource
})
},
append: (string) => {
mutations.push((source) => {
const concatSource = new ConcatSource(source, string)
return concatSource
})
},
replace: ({ start, end, replacement }) => {
mutations.push((source) => {
const replaceSource = new ReplaceSource(source)
replaceSource.replace(start, end, replacement)
return replaceSource
})
},
insert: ({ position, insertion }) => {
mutations.push((source) => {
const replaceSource = new ReplaceSource(source)
replaceSource.insert(position, insertion)
return replaceSource
})
},
toContentAndSourcemap: (options) => {
const lastSource = mutations.reduce((previous, mutation) => {
return mutation(previous)
}, firstSource)
const { source, map } = lastSource.sourceAndMap(options)
return {
content: source,
sourcemap: map,
}
},
}
}
import { assert } from "@jsenv/assert"
import { createMagicSource } from "./magic_source.js"
{
const magicSource = createMagicSource({
url: "file:///file.js",
content: "console.log(42)",
map: null,
})
magicSource.prepend("foo")
magicSource.append("bar")
const { content } = magicSource.toContentAndSourcemap()
const actual = content
const expected = `fooconsole.log(42)bar`
assert({ actual, expected })
}
{
const magicSource = createMagicSource({
url: "file:///file.js",
content: "ZZaaZZ",
map: null,
})
magicSource.replace({
start: 2,
end: 3,
replacement: "b",
})
magicSource.replace({
start: 2,
end: 2,
replacement: "ccc",
})
const { content } = magicSource.toContentAndSourcemap()
const actual = content
const expected = `ZZcccZZ`
assert({ actual, expected })
}
@dmail
Copy link
Author

dmail commented Mar 1, 2022

Unfortunately webpack-sources fails to override (it erases the end of the line).
Moreover by using @ampproject/remapping we can compose an original sourcemap with a sourcemap from magic-string

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment