esrewrite
Rewrite file specifiers to point to new locations across source files that may
vary in their content type. Useful for renaming files in bulk.
Usage
You need two inputs to use the program: the list of files that were renamed and
a graph that outlines the dependencies between the files, including those that
were not renamed.
esrewrite(
renames: Array.<Array.<Path, Path>>,
dependencyGraph: Map.<
dependencies: Map.<Path, Object>,
dependents: Map.<Path, Object>
>,
options: Map
)
Example
Consider a simple scenario where the file src/a.js
is being renamed to
src/new-a.js
.
const renames = [
[ 'src/a.js', 'src/new-a.js' ]
]
const graph = {
dependencies: {
'src/a.js': [],
'src/b.js': [{ id: 'src/a.js', userRequest: './a' }]
},
dependents: {
'src/a.js': [{ id: 'src/b.js', userRequest: './a' }],
'src/b.js': []
}
}
esrewrite(renames, graph, {
parsers: [
{
when: file => file.endsWith('.js'),
use: require('esrewrite/parsers/javascript')
}
]
})
After applying, src/b.js
now imports src/a-new.js
instead of src/a.js
.
Options
{
context: Path,
dry: Boolean,
stats: Map.<
warnings: Array.<String>,
mods: Array.<String>
>,
include: Array.<Union.<Path, RegExp, Minimatch>>,
exclude: Array.<Union.<Path, RegExp, Minimatch>>,
ignore: Array.<Union.<Path, RegExp, Minimatch>>,
additionalRequests: Map.<Path, Map.<Path, String>>,
parsers: Array.<
Map.<
when: (Path): Boolean,
use: Map.<
parse: (String): Any,
walk: (Any, Function): void,
>
>
>,
mods: Array.<
Map.<
when: (Path): Boolean,
apply: (ParsingContext): void
>
>,
optimize: (Path, Path, Object.<request: String>): String,
}
Parsing
A parser implements two interfaces:
parse: (String): Any
The output of which, usually an AST, is fed to the walk routine:
walk: (Any, Function): void
Walk is what esrewrite cares most about; it applies the visitor function to
every node extracted in the parse routine. The visitor is a mod that is
responsible for actually modifying the contents of the file.
Modding
A mod is a function that is applied to a single file and gets provided with all
the parameters it may need to perform the rewrites:
file
: the file being rewritten
lines
: array of lines of the file contents; this is what the mod should be mutating
text
: buffer containing the file contents; don't modify this
walk
: the parser's walk routine that can visit every structural node in the file
requests
: a map of the rewrites for the file, key is the old request and
value is the new request
stats
: the stats objects that the mod can write to
originals
: a mapping of renamed files to their original locations
renamed
: a mapping of original files to their renamed locations
For every adjustment made, be sure to log it in stats.mods
. For warnings,
write to stats.warnings
.
See existing mods under ./lib/mods/
for guidance.
Optimizing
Specifiers can be tuned to better mimic what a human would write. This is
especially relevant if the renames use absolute filepaths as you probably
do not want that in source files.
The optimize
interface enables this. It receives the following parameters:
- the target file path
- the file being rewritten (context file)
- the original request
The output of optimize
must be a string to be used in place of the target's
filepath.
Here is a sample optimizer that roots all filepaths to the current working
directory:
{
optimize: (target, context, { request }) => {
return require('path').relative(process.cwd(), target)
}
}