-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
added 'isLocated' flag to operations that receive indexes as arguments. #26
Conversation
Current coverage is
|
# Conflicts: # src/MagicString/index.js
@Rich-Harris what do you think? |
@amir-arad Hi! Thanks for the PR and sorry for the radio silence, been short of time lately. My initial response is that this isn't the right API – it's a classic example of the Boolean trap. Given that you're essentially trying to do two very different things depending on whether I'm curious about the intended use – could you elaborate? We might be able to come up with something better. |
@Rich-Harris I Would love to hear your feedback and advice! I'm writing a visitors engine. It's designed function is a fast pre-transpiler that produces intermediate code that will be sent to a transpiler as input. Visitors can delete or insert text at any position and in any order. A visitor may overwrite a text section while a later visitor may insert text at the beginning or end of that section, using the first or last index of the deleted section as the location of insertion, which causes an error to be thrown by MagiString. This error is part of the tested behaviors and provides helpful feedback, only that in my case I would like to bypass it both for functionality reasons and for performance (so try-catch is not an option). In such cases I would like to 'snap' the insertion to the edges past the deleted section, so it happens in the nearest valid location. So I have this workaround in place: execute(actionList){
actionList.forEach(action => {
var start = this.locate(action.start);
var end = this.locate(action.end);
this.magicString.overwrite(start, end, action.str);
});
}
private locate(idx) {
var result = this.magicString.locate(idx);
if (result === null && idx > 0){
result = this.magicString.locate(idx-1);
}
if (result === null && idx < this.magicString.toString().length){
result = this.magicString.locate(idx+1);
}
if (result === null){
throw new Error( `Visitor referring an outdated location ${idx}`);
}
return this.magicString.locateOrigin(result);
}; As you see, I'm locating each index, correcting it (or throwing an error myself), then locating it's origin so that I can send it to the What do you think? |
Thinking aloud here: it sounds like the need, ultimately, is to be able to update 'patches' after they've been applied. Maybe this would be a more flexible library if it worked that way internally – rather than destructively updating a string internally, and updating the location map with each edit, maybe it non-destructively keeps track of which patches have been applied. The API could work exactly as it does now, with the same restrictions, except that you could do this sort of thing... let patch = magicString.findPatch( 42 );
// Patch {
// start: 40,
// end: 50,
// content: 'REPLACEMENT',
// original: 'abcdefghij'
// }
patch.prepend( 'THIS IS A ' ).append( ' STRING' ).replace( 'REPLACEMENT', 'NEW' );
// Patch {
// start: 40,
// end: 50,
// content: 'THIS IS A NEW STRING',
// original: 'abcdefghij'
// } ...or it could become more flexible, by losing some of the implementation-mandated restrictions. It should be more performant as well – no need to adjust every character index that follows an edit (which is only necessary in case you're generating a sourcemap, which isn't always the case). What do you reckon? Tempted to have a crack at this, it seems like a more sensible design. |
I was leaning towards writing something in the lines of the patches solution just before I discovered MagicString. |
@amir-arad yeah, Anyway, good news – I just did some stress testing and as of this PR, making changes is several hundred times faster, and generating sourcemaps (the most time-consuming part) is roughly 25-30x faster – all in all about 35-40x performance improvement. (The test was just replacing every |
👍 for the perf. boost, no surprise there I guess. |
Added the option for the user to supply indexes based on the current state of the string, instead of the original string.