Migrate to scriptlets and get rid of JS rules
@ameshkov commented on Wed Feb 08 2017
Adguard scriptlet is a named script, which can be used further by JS or basic rules. Scriptlets are configured in a special "scriptlets" configuration file and maintained by us.
Why do we need it
- JS rules are simply hard to support. We currently have more than 700 JS rules in all the AG filters, and the number is growing.
- Some JS rules are almost identical. For instance, Object.defineProperty(window) is used by ~200 rules.
- AMO and Opera review. It will make reviewers life much easier.
I don't say we should get rid of JS rules completely, though. It should be allowed in the user filter, just not in other filters.
Scriptlets configuration file will be updated automatically along with the filters. However, in the case of AMO and Opera, automatic update will be disabled so that we comply with remote scripts policy.
Scriptlets usage syntax
There are two options.
Injecting and executing scriptlet on a per-domain basis:
example.org#&#scriptlet:scriptletName(param1, param2);
Replacing JS file content with a scriptlet
I am not sure about it, though. I suppose we should start with injection only.
||example.org/file.js$replace=scriptlet:scriptletName(param1, param2);
Scriptlets configuration file
Here is an example of the scriptlet configuration file.
/**
* Scriptlets configuration object.
*/
var scriptlets = {
// Scriptlets file version
version: "1.0.0"
};
/**
* Empty scriptlet, just to show you the idea.
*
* @param context Scriptlet execution context
*/
scriptlets["empty"] = function(context) {
// context.log Prints message to the console
// context.version Scriptlets configuration file version
context.log(context.version);
// scriptlet parameter
console.log(context.params[0]);
};
/**
* Defines "window" property.
*
* Example:
* example.org#%#scriptlet:defineWindowProperty("test", 1);
*/
scriptlets["defineWindowProperty"] = function(context) {
var propertyName = context.params[0];
var propertyValue = context.params[1];
Object.defineProperty(window, propertyName, {
get: function() {
if (typeof(propertyValue) === "undefined") {
return;
}
return propertyValue;
},
set: function() {}
});
};
@ameshkov commented on Wed Feb 08 2017
@atropnikov @seanl-adg @Alex-302 Guys, I need your feedback on this proposition.
@Alex-302 commented on Wed Feb 08 2017
Are scriptlets will be hardcoded for AMO version as before?
Replacing JS file content with a scriptlet
is it possible to replace only specific function in the file(for example in some library)?
@ameshkov commented on Wed Feb 08 2017
Are scriptlets will be hardcoded for AMO version as before?
The difference between AMO, Opera, and other versions will be that scriptlets configuration file won't be updated automatically.
is it possible to replace only specific function in the file(for example in some library)?
No, that's possible with $replace rules only.
@ameshkov commented on Wed Feb 08 2017
I've found the first problem with the proposed syntax; it is not backward compatible with the old JS rules, so it will break previous versions of Adguard.
We should "mark" them differently, use #&# mark instead of #%#. I've updated the first message.
@ameshkov commented on Wed Apr 26 2017
What we also need:
- Add support for the base64-encoded resources (transparent.png and such)
- Scriptlet should have more props, content type for instance.
- We should also handle Content-MD5 header properly
@ameshkov commented on Thu Jul 27 2017
@seanl-adg
- We should have unit-tests for scriptlets.
- Consider having scriptlets dependencies. Do we actually need it?
- I suppose that base64-encoded resource redirects should be a separate structure, otherwise it may cause confusion.