AdGuard's JavaScript library of Scriptlets and Redirect resources
npm install @adguard/scriptletsAdGuard's Scriptlets and Redirect resources library which provides extended capabilities for content blocking.
- Scriptlets
- Syntax
- Blocking rules
- Exception rules
- Available scriptlets
- Scriptlets compatibility table
- Trusted scriptlets
- Restriction
- Available trusted scriptlets
- Redirect resources
- Syntax
- Available redirect resources
- Redirect resources compatibility table
- Development
- How to build
- How to test
- How to link packages
- How to update wiki
- Usage
- CoreLibs
- NPM module
- API description
- Scriptlets API
- invoke()
- getScriptletFunction()
- Properties
- SCRIPTLETS_VERSION
- ContentScriptApi
- PolicyApi
- Redirects API
- Redirects class
- getRedirect()
- isBlocking()
- getRedirectFilename()
- Validators API
- isValidScriptletName()
- isValidScriptletRule()
- isAdgScriptletRule(), isUboScriptletRule(), isAbpSnippetRule()
- isValidAdgRedirectRule()
- isRedirectResourceCompatibleWithAdg()
- Converters API
- convertUboToAdg()
- convertAbpToAdg()
- convertScriptletToAdg()
- convertAdgToUbo()
- convertAdgRedirectToUbo()
- Browser compatibility
- Projects using Scriptlets
*
Scriptlet is a JavaScript function which can be used in a declarative manner in AdGuard filtering rules.
AdGuard supports a lot of different scriptlets.
Please note, that in order to achieve cross-blocker compatibility, we also support syntax of uBO and ABP.
``text`
[domains]#%#//scriptlet(name[, arguments])
- domains — optional, a list of domains where the rule should be applied;name
- — required, a name of the scriptlet from AdGuard Scriptlets library;arguments
- — optional, a list of string arguments (no other types of arguments are supported).
> Remarks
>
> - The meaning of the arguments depends on the scriptlet.
>
> - Special characters in scriptlet argument must be escaped properly:
> - valid:
> - 'prop["nested"]'"prop['nested']"
> - 'prop[\'nested\']'
> - "prop[\"nested\"]"
> - 'prop['nested']'
> - not valid:
> - "prop["nested"]"
> - name
>
> - Scriptlet and each of the arguments should be wrapped in quotes.".css('display','block');"
> You can use either single or double quotes for the scriptlet name and arguments.
> Single quote is recommended but not for cases when its usage makes readability worse,
> e.g. is more preferred then '.css(\'display\',\'block\');'.
`text`
[domains]#@%#//scriptlet([name[, arguments]])
- domains — optional, a list of domains where the rule should be applied;name
- — optional, a name of the scriptlet to except from the applying;arguments
if not set, all scriptlets will not be applied;
- — optional, a list of string arguments to match the same blocking rule and disable it.
#### Examples
1. Apply the abort-on-property-read scriptlet on all pages of example.org and its subdomains,alert
and passes one argument to it ():
`adblock`
example.org#%#//scriptlet('abort-on-property-read', 'alert')
1. Remove the branding class from all div[class^="inner"] elementsexample.org
on all pages of and its subdomains:
`adblock`
example.org#%#//scriptlet('remove-class', 'branding', 'div[class^="inner"]')
1. Apply set-constant and set-cookie on any webpage,set-constant
but because of specific scriptlet exception rule
only scriptlet will be applied on example.org and its subdomains:
`adblock`
#%#//scriptlet('set-constant', 'adList', 'emptyArr')
#%#//scriptlet('set-cookie', 'accepted', 'true')
example.org#@%#//scriptlet('set-cookie')
1. Apply adjust-setInterval on any webpage,set-local-storage-item
and on all pages of example.com and its subdomains,example.com
but there is also multiple scriptlet exception rule,
so no scriptlet rules will be applied on and its subdomains:
`adblock`
#%#//scriptlet('adjust-setInterval', 'count', '*', '0.001')
example.com#%#//scriptlet('set-local-storage-item', 'ALLOW_COOKIES', 'false')
example.com#@%#//scriptlet()
- Scriptlets list
- Scriptlets compatibility table
Trusted scriptlets are scriptlets with extended functionality.
Their names are prefixed with trusted-, e.g trusted-click-element,
to be easily distinguished from common scriptlets.
Trusted scriptlets application must be restricted due to dangerous nature of their capabilities.
Allowed sources of trusted scriptlets are:
- filters created by AdGuard Team,
- custom filters which were installed as trusted,
- user rules.
> Trusted scriptlets has no compatibility table as they are not compatible with any other blocker.
AdGuard is able to redirect web requests to a local "resource".
AdGuard uses the same filtering rule syntax as [uBlock Origin][ubo-redirect].
Also, it is compatible with ABP $rewrite=abp-resource modifier.
$redirect is a modifier for [the basic filtering rules][kb-basic-rules]$domain
so rules with this modifier support all other basic modifiers like , $third-party, $script, etc.
The value of the $redirect modifier must be the name of the resource that will be used for redirection.
See the list of available redirect resources.
> Priority of $redirect rules is described in the [Knowledge Base][kb-redirect-priority].
- ||example.org/script.js$script,redirect=noopjs — redirects all requests to script.jsnoopjs
to the resource named .||example.org/test.mp4$media,redirect=noopmp4-1s
- — requests to example.org/test.mp4 will be redirectednoopmp4-1s
to the resource named .
> uBlock Origin specifies additional resource name none that can disable other redirect rules.$badfilter
> AdGuard does not support it, use to disable specific rules.
- Redirect resources list
- Redirect resources compatibility table
*
Install dependencies:
`bash`
pnpm install
Build dist:
`bash`
pnpm build
In tsurlfilter directory install and link dependencies, link scriptlets,
move into package and build, and create tsurlfilter link.
`bash
lerna bootstrap
pnpm link --global "@adguard/scriptlets"
cd ./packages/tsurlfilter
pnpm build
pnpm link --global
`
In extension directory install dependencies, link packages and build
` bash
pnpm install
pnpm link --global "@adguard/scriptlets"
$3
Some tests are run in QUnit, some in Vitest.
Run all tests:
`bash
pnpm test
`1. QUnit is used for testing of scriptlets, redirects, and helpers:
`text
pnpm test:qunit [scriptlets | redirects | helpers]
` For scriptlets and redirects test run can be more specific:
`bash
// node test run
pnpm test:qunit scriptlets --name set-cookie
pnpm test:qunit redirects --name ati-smarttag // gui test run
pnpm test:qunit scriptlets --name set-cookie --gui
pnpm test:qunit redirects --name ati-smarttag --gui
` For debugging purposes after some test is running in gui mode,
you may change your scriptlet/redirect code, and without stopping the server
run in new terminal:
`bash
pnpm test:qunit scriptlets --name set-cookie --build
`1. Run all jest tests:
`bash
pnpm test:vitest
` or limit the testing —
include may be specified in vitest.config.ts
or specify test name in command line, e.g.:
`bash
pnpm test:vitest -t isValidScriptletRule
`To run browserstack tests create
.env file or copy and rename .env-example.Fill in
and with data from your Browserstack profile.
Run next command:`bash
pnpm browserstack
`Tests run by
jest should be named .spec.js, so they will be not included in the QUnit tests.#### Debugging
Use
debugger; statement where you need it, run`bash
pnpm test
`and open needed HTML file from
tests/dist in your browser with devtools
$3
Scriptlets library relies on external packages, such as
@adguard/agtree.
During development, you might need to link these packages using pnpm link.$3
There are two scripts to update wiki:
1.
pnpm wiki:build-table — checks compatibility data updates and updates the compatibility table.
Should be run manually while the release preparation.
1. pnpm wiki:build-docs — updates wiki pages about-scriptlets.md and about-redirects.md.
They are being generated from JSDoc-type comments of corresponding scriptlets and redirects source files
due to @scriptlet/@redirect and @description tags. Runs automatically while the release build. Usage
$3
For CoreLibs usage you should use
dist/scriptlets.corelibs.json and dist/redirects.json.File example:
`json
{
"version": "1.0.0",
"scriptlets": [
{
"names": [
"abort-on-property-read",
"ubo-abort-on-property-read.js",
"abp-abort-on-property-read"
],
"scriptlet": "function() { ...code... }"
}
]
}
`Schema:
`json
{
"type": "object",
"properties": {
"version": {
"type": "string"
},
"scriptlets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"names": {
"type": "array",
"items": {
"type": "string"
}
},
"scriptlet": {
"type": "string"
}
}
}
}
}
}
`$3
#### Installation
You can install the library using
- [Yarn][yarn-pkg-manager-url]:
yarn add @adguard/scriptlets
- [NPM][npm-pkg-manager-url]: npm install @adguard/scriptlets
- [PNPM][pnpm-pkg-manager-url]: pnpm add @adguard/scriptlets API description
$3
You are welcome to use scriptlets as a CJS modules or ESM modules:
`typescript
const { scriptlets } = require('@adguard/scriptlets');
// or
import { scriptlets } from '@adguard/scriptlets';
`invoke()`typescript
/**
* Returns scriptlet code by source.
*
* @param source Scriptlet properties.
*
* @returns Scriptlet code.
* @throws An error on unknown scriptlet name.
*/
declare function getScriptletCode(source: Source): string;
declare const scriptlets: {
invoke: typeof getScriptletCode;
};
`where
Source is:`typescript
interface Source {
/**
* Scriptlet name
*/
name: string;
/**
* Arguments for scriptlet function
*/
args: string[];
/**
* {'extension'|'corelibs'} engine Defines the final form of scriptlet string presentation
*/
engine: string;
/**
* Version
*/
version: string;
/**
* flag to enable printing to console debug information
*/
verbose: boolean;
/**
* Source rule text is used for debugging purposes.
*
* @deprecated since it is not used in the code anymore.
*/
ruleText?: string;
/**
* Domain name, used to improve logging
*/
domainName?: string;
/**
* Optional unique identifier for a scriptlet instance.
*
* This identifier is used to prevent multiple executions of the same scriptlet on the page.
* If provided, this uniqueId will be combined with the scriptlet's name and args
* to create a unique identifier for the scriptlet call. This identifier is
* stored in the Window.prototype.toString object to ensure the scriptlet
* is not executed more than once in the same context.
*
* By avoiding multiple executions, it helps in reducing redundant operations and
* potential side effects that might occur if the same scriptlet is called multiple times.
*
* If uniqueId is not specified, no such unique identifier is created, and the
* scriptlet can be called multiple times.
*/
uniqueId?: string;
/**
* Instance of content script provided API.
*
* Property optional because:
* - for backwards compatibility.
* - currently only CoreLibs provides this API.
*/
api?: ContentScriptApi;
}
`ContentScriptApi for more details.getScriptletFunction()`typescript
/**
* Returns scriptlet function by name.
*
* @param {string} name Scriptlet name
*
* @returns {Function} — Scriptlet function.
*/
declare function getScriptletFunction(name: any): string;
declare const scriptlets: {
getScriptletFunction: typeof getScriptletFunction;
};
`SCRIPTLETS_VERSIONtype:
stringCurrent version of scriptlets library.
ContentScriptApiAPI provided by CoreLibs content script.
This API is used to provide a set of utilities and shared state for scriptlets
running in the context of a web page. Particularly, it includes:
`typescript
export interface ContentScriptApi {
/**
* Trusted Types Policy API utilities.
*/
readonly policy: PolicyApi; /**
* Shared state between different script and scriptlet rules.
*
* This object acts as a centralized repository for shared data.
* - Keys represent the unique identifiers or names of the shared data.
* - Values can be of any type and should correspond to the specific data shared across script rules.
*
* Example:.
*
`adguard
* ! Modify in one script rule
* #%#api.shared.testKey = 'testValue'
*
* ! Access in another (logs 'testValue')
* #%#console.log(api.shared.testKey)
* `
*/
readonly shared: Record;
}
`PolicyApiTrusted Types Policy API utility.
This interface extends the native
TrustedTypePolicy and TrustedTypePolicyFactory
to provide a more user-friendly API for working with Trusted Types. In case if
environment doesn't support Trusted Types API, it provides polyfilled methods
and properties to ensure compatibility.`typescript
export interface PolicyApi extends TrustedTypePolicy, TrustedTypePolicyFactory {
/**
* Is Trusted Types API supported.
*/
isSupported: boolean; /**
* TrustedType enum attached to PolicyApi.
*
* Reason why we attach it to instance because inside
* of script and scriptlet we can't import and to not
* pollute global env with custom variables.
*
* @example
* api.policy.TrustedType.HTML // "TrustedHTML"
*/
TrustedType: typeof TrustedType;
/**
* Creates Trusted Type depending on
type:
* - TrustedHTML
* - TrustedScript
* - TrustedScriptURL
* - or returns back input if none of them applicable.
*
* @example
* divElement.innerHTML = api.policy.create(api.policy.TrustedType.HTML, '');
*
* @param type Trusted Type.
* @param input Input from which creates Trusted Type.
* @returns Created value.
*/
create(type: TrustedType, input: string): string; /**
* Converts
value of attribute into one of the Trusted Types:
* - TrustedHTML
* - TrustedScript
* - TrustedScriptURL
* - or returns back value if none of them applicable (null).
*
* @example
* const trustedScriptURL = api.policy.convertAttributeToTrusted("script", "src", 'SOME_URL');
* scriptElement.setAttribute("src", trustedScriptURL);
*
* @param tagName Name of an HTML tag.
* @param attribute Attribute.
* @param value Value of attribute that needs to be converted.
* @param elementNS Element namespace, if empty defaults to the HTML namespace.
* @param attrNS Attribute namespace, if empty defaults to null.
* @returns Converted value.
*/
convertAttributeToTrusted(
tagName: string,
attribute: string,
value: string,
elementNS?: string,
attrNS?: string,
): string; /**
* Converts
value of property into one of the Trusted Types:
* - TrustedHTML
* - TrustedScript
* - TrustedScriptURL
* - or returns back value if none of them applicable (null).
*
* @example
* divElement.innerHTML = api.policy.convertPropertyToTrusted("div", "innerHTML", "");
*
* @param tagName Name of an HTML tag.
* @param property Property.
* @param value Value or property.
* @param elementNS Element namespace, if empty defaults to the HTML namespace.
* @returns Converted value.
*/
convertPropertyToTrusted(
tagName: string,
property: string,
value: string,
elementNS?: string,
): string;
}
`- TrustedTypePolicy interface
- TrustedTypePolicyFactory interface
$3
You are welcome to use redirects as a CJS modules or ESM modules:
`javascript
const { Redirects } = require('@adguard/scriptlets/redirects');
// or
import { Redirects, getRedirectFilename } from '@adguard/scriptlets/redirects';
``typescript
import { Redirects } from '@adguard/scriptlets';/**
* Converts rawYaml into JS object with sources titles used as keys
*/
const redirects = new Redirects(rawYaml)
`where
rawYaml is a string with YAML content located in dist/redirects.yml.getRedirect()`typescript
/**
* Returns redirect source object by title
*/
const redirect = redirects.getRedirect('noopjs');/**
* Redirect is an object with following props:
* {
* title: 1x1-transparent.gif
* comment: http://probablyprogramming.com/2009/03/15/the-tiniest-gif-ever
* contentType: image/gif;base64
* content: R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
* }
*/
`isBlocking()`typescript
/**
* Check if redirect is blocking, e.g. click2load.html
*/
const isBlocking = redirect.isBlocking('click2load.html');
`getRedirectFilename()`typescript
import { getRedirectFilename } from '@adguard/scriptlets/redirects';
/**
* For a given name or alias of redirect returns the corresponding filename
* @param name Name or alias of redirect
* @returns Redirect's filename with extension
*/
declare function getRedirectFilename(name: string): string;
`$3
isValidScriptletName()`typescript
import { isValidScriptletName } from '@adguard/scriptlets/validators';/**
* Checks whether the
name is valid scriptlet name.
* Uses cache for better performance.
*
* @param name Scriptlet name.
* @returns True if scriptlet name is a valid one or an empty string,
* otherwise false.
*/
declare function isValidScriptletName(name: string | null): boolean;
`isValidScriptletRule()`typescript
/**
* 1. For ADG scriptlet checks whether the scriptlet syntax and name are valid.
* 2. For UBO and ABP scriptlet first checks their compatibility with ADG
* by converting them into ADG syntax, and after that checks the name.
*
* ADG or UBO rules are "single-scriptlet", but ABP rule may contain more than one snippet
* so if at least one of them is not valid — whole ruleText rule is not valid too.
*
* @param rule Any scriptlet rule — ADG or UBO or ABP.
*
* @returns True if scriptlet name is valid in rule.
*/
declare function isValidScriptletRule(rule: string | ScriptletInjectionRule): boolean;
`isAdgScriptletRule(), isUboScriptletRule(), isAbpSnippetRule()`typescript
/**
* Checks if the rule is AdGuard scriptlet rule
*
* @param rule - rule text
* @returns true if given rule is adg rule
*/
declare function isAdgScriptletRule(rule: string): boolean;/**
* Checks if the
rule is uBO scriptlet rule
*
* @param rule rule text
* @returns true if given rule is ubo rule
*/
declare function isUboScriptletRule(rule: string): boolean;/**
* Checks if the
rule is AdBlock Plus snippet
*
* @param rule rule text
* @returns true if given rule is abp rule
*/
declare function isAbpSnippetRule(rule: string): boolean;
`isValidAdgRedirectRule()`typescript
/**
* Checks if the rule is valid AdGuard redirect resource rule
*
* @param rule - rule text
* @returns true if given rule is valid adg redirect
*/
declare function isValidAdgRedirectRule(rule: string): boolean
`isRedirectResourceCompatibleWithAdg()`typescript
/**
* Checks if the specified redirect resource is compatible with AdGuard
*
* @param redirectName - Redirect resource name to check
* @returns - true if the redirect resource is compatible with AdGuard
*/
declare function isRedirectResourceCompatibleWithAdg(redirectName: string): boolean;
`$3
`typescript
import {
convertUboToAdg,
convertAbpToAdg,
convertScriptletToAdg,
convertAdgToUbo
} from '@adguard/scriptlets/converters';
`convertUboToAdg()`typescript
/**
* Converts string of UBO scriptlet rule to AdGuard scriptlet rule
*
* @param rule UBO scriptlet rule
* @returns array with one AdGuard scriptlet rule
*
* @deprecated
*/
declare function convertUboToAdg(rule: string | ScriptletInjectionRule): string[];
`> Note that parameters in UBO rule should be separated by comma + space. Otherwise, the rule is not valid.
convertAbpToAdg()`typescript
/**
* Convert string of ABP snippet rule to AdGuard scriptlet rule
*
* @param rule ABP snippet rule
* @returns array of AdGuard scriptlet rules, one or few items depends on Abp-rule
*/
declare function convertAbpToAdg(rule: string | ScriptletInjectionRule): string[];
`convertScriptletToAdg()`typescript
/**
* Converts any scriptlet rule into AdGuard syntax rule.
* Comments and non-scriptlet rules are returned without changes.
*
* @param rule Rule.
*
* @returns Array of AdGuard scriptlet rules: one array item for ADG and UBO or few items for ABP.
* For the ADG rule validates its syntax, and returns an empty array if it is invalid.
*/
declare function convertScriptletToAdg(rule: string | ScriptletInjectionRule): string[];
`convertAdgToUbo()`typescript
/**
* Converts AdGuard scriptlet rule to UBO syntax.
*
* @param rule AdGuard scriptlet rule
* @returns UBO scriptlet rule
* or undefined if rule is not valid AdGuard scriptlet rule.
*/
declare function convertAdgToUbo(rule: string | ScriptletInjectionRule): string | undefined;
`convertAdgRedirectToUbo()`typescript
/**
* Converts Adg redirect rule to Ubo one
* 1. Checks if there is Ubo analog for Adg rule
* 2. Parses the rule and checks if there are any source type modifiers which are required by Ubo
* and if there are no one we add it manually to the end.
* Source types are chosen according to redirect name
* e.g. ||ad.com^$redirect=,important ->> ||ad.com^$redirect=,important,script
* 3. Replaces Adg redirect name by Ubo analog
*
* Note: if adg redirect uses UBO's priority syntax, it will be lost on conversion, e.g:
* ||example.com$redirect=noopjs:99 => ||example.com$redirect=noop.js
*
* @param rule adg rule
* @returns converted ubo rule
* @throws on incompatible rule
*/
declare function convertAdgRedirectToUbo(rule: string): string;
` Browser Compatibility
| Browser | Version |
|-----------------------|:--------|
| Chrome | ✅ 55 |
| Firefox | ✅ 52 |
| Edge | ✅ 15 |
| Opera | ✅ 42 |
| Safari | ✅ 13 |
| Internet Explorer | ❌ |
Projects using Scriptlets
- CoreLibs (updates automatically)
- TSUrlFilter
- FiltersCompiler
(
tsurlfilter's update might be required as well)
- AdguardBrowserExtension
(tsurlfilter also should be updated)
- AdguardForSafari (adguard-resources should be updated)
- AdguardForiOS
(tsurlfilter should be updated in advanced-adblocker-web-extension`)[ubo-redirect]: https://github.com/gorhill/uBlock/wiki/Static-filter-syntax#redirect
[kb-basic-rules]: https://adguard.com/kb/general/ad-filtering/create-own-filters/#basic-rules
[kb-redirect-priority]: https://adguard.com/kb/general/ad-filtering/create-own-filters/#redirect-rule-priorities
[yarn-pkg-manager-url]: https://yarnpkg.com/en/docs/install
[npm-pkg-manager-url]: https://www.npmjs.com/get-npm
[pnpm-pkg-manager-url]: https://pnpm.io/installation