From d67bcc24f5092de410a18b0ac7a48ff9254a6907 Mon Sep 17 00:00:00 2001 From: Slava Leleka Date: Wed, 3 Apr 2024 18:11:44 +0300 Subject: [PATCH] update syntax highlighting for exception scriptlet rules. #132 AG-31622 Squashed commit of the following: commit 316513f5baadb0e5d6445f0d7dda493f7a1ce59c Author: scripthunter7 Date: Tue Apr 2 19:08:31 2024 +0200 small improvements commit bc76fc767ff0dbaf72bf14f13479abeda2f742ba Author: Slava Leleka Date: Tue Apr 2 20:03:24 2024 +0300 update changelog commit f6bed55d10014ea52773919d8f097a3154a82d64 Merge: 963e15d 32bd831 Author: Slava Leleka Date: Tue Apr 2 18:31:07 2024 +0300 Merge branch 'fix/AG-31622' of ssh://bit.int.agrd.dev:7999/adguard-filters/vscode-adblock-syntax into fix/AG-31622 commit 963e15debf0b574046873d9a839d996de5317a10 Author: Slava Leleka Date: Tue Apr 2 18:27:32 2024 +0300 fix linter commit 32bd83128c14fecba369088b81d35b82431fad22 Author: scripthunter7 Date: Tue Apr 2 17:27:06 2024 +0200 fix linter commit af7f0a605445658e0f4b5f901bc6f0a7e5ae2d82 Author: Slava Leleka Date: Tue Apr 2 18:20:20 2024 +0300 update changelog commit aee8fe920a0bc26197613de574896b51298bfe66 Author: Slava Leleka Date: Tue Apr 2 18:15:01 2024 +0300 add tests commit 31e2e8877e5f452c658aa0affb46c06cd0546c0d Author: Slava Leleka Date: Tue Apr 2 18:10:31 2024 +0300 fix scriptlet match commit 4514d5a15056156e9965de3c1d9d595b53033328 Author: Slava Leleka Date: Tue Apr 2 17:55:14 2024 +0300 update vscode-oniguruma commit 2a6e823f2bd04a58449428ef480b8d4a77f03832 Author: scripthunter7 Date: Tue Apr 2 15:58:59 2024 +0200 update test rules commit 4cdb98aa785cf7ed5ed95783f158cefa2f0ada80 Author: scripthunter7 Date: Tue Apr 2 15:58:45 2024 +0200 update syntax highlighting Co-authored-by: Slava --- CHANGELOG.md | 8 ++ package.json | 2 +- syntaxes/adblock.yaml-tmlanguage | 56 +++++++++++- test/grammar/comments/comment.test.ts | 2 + test/grammar/cosmetic/scriptlet.test.ts | 115 ++++++++++++++++++++++++ test/static/rules/test_rules.txt | 8 ++ yarn.lock | 8 +- 7 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 test/grammar/cosmetic/scriptlet.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c3bf4bb..820d7a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog][keepachangelog], and this project adheres to [Semantic Versioning][semver]. +## 1.1.8 - 2024-04-03 + +### Fixed + +- Highlighting for `#@%#//scriptlet()` like rules: [#132] + +[#132]: https://github.com/AdguardTeam/VscodeAdblockSyntax/issues/132 + ## 1.1.7 - 2024-01-10 diff --git a/package.json b/package.json index 6eecb3c..54669b2 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "tsx": "^4.7.0", "typescript": "^4.9.5", "unified": "^11.0.4", - "vscode-oniguruma": "^1.7.0", + "vscode-oniguruma": "^2.0.1", "vscode-textmate": "^9.0.0", "yaml": "^2.2.2" } diff --git a/syntaxes/adblock.yaml-tmlanguage b/syntaxes/adblock.yaml-tmlanguage index 51ac87f..5004553 100644 --- a/syntaxes/adblock.yaml-tmlanguage +++ b/syntaxes/adblock.yaml-tmlanguage @@ -213,7 +213,57 @@ repository: - include: "#contentAttributes" scriptletRules: patterns: - - match: "^(\\[.+?\\])?(.*?)(#@?%#)(\\/\\/scriptlet)(\\()(.+)(\\)\\s*)$" + - include: "#exceptionScriptletRules" + - include: "#blockingScriptletRules" + exceptionScriptletRules: + patterns: + - match: |- + (?x) + ^ # Start of the line + \s* # Optional leading whitespace + (\[.+?\])? # Group 1. AdGuard modifier list + (.*)? # Group 2. Domain list + (\#@%\#) # Group 3. Cosmetic rule marker + (\/\/scriptlet) # Group 4. Scriptlet marker + (\() # Group 5. Opening parenthesis + (.*)? # Group 6. Arguments + (\)) # Group 7. Closing parenthesis + \s* # Optional trailing whitespace + $ # End of the line + captures: + "1": + patterns: + - include: "#cosmeticRulesOptions" + "2": + patterns: + - include: "#domainListCommaSeparated" + "3": + name: keyword.control.adblock + "4": + name: entity.name.function.adblock + "5": + name: punctuation.section.adblock + "6": + patterns: + - include: "#emptyScriptletFunction" + - include: "#scriptletFunction" + "7": + name: punctuation.section.adblock + blockingScriptletRules: + patterns: + - match: |- + (?x) + ^ # Start of the line + \s* # Optional leading whitespace + (\[.+?\])? # Group 1. AdGuard modifier list + (.*)? # Group 2. Domain list + (\#%\#) # Group 3. Cosmetic rule marker + (\/\/scriptlet) # Group 4. Scriptlet marker + (\() # Group 5. Opening parenthesis + (.*\S.*) # Group 6. Arguments. Note: we look for a parameter that contain at least one non-whitespace character + (\)) # Group 7. Closing parenthesis + \s* # Optional trailing whitespace + $ # End of the line captures: "1": patterns: @@ -568,6 +618,10 @@ repository: name: punctuation.section.adblock - name: invalid.illegal.adblock match: ".*" + emptyScriptletFunction: + patterns: + - match: \s*\z + name: entity.name.section.adblock.empty-scriptlet scriptletFunction: patterns: - match: ((['|"])(.*?)(? { '#$?#.selector:has(> .selector) { display: none; }', '#@$?#.selector:has(> .selector) { display: none; }', '#%#//scriptlet(\'adg-scriptlet0\', \'arg0\', \'arg1\', \'arg2\')', + "#@%#//scriptlet('adg-scriptlet0')", + '#@%#//scriptlet()', '#@%#//scriptlet(\'adg-scriptlet0\', \'arg0\', \'arg1\', \'arg2\')', '$$div', '$@$div', diff --git a/test/grammar/cosmetic/scriptlet.test.ts b/test/grammar/cosmetic/scriptlet.test.ts new file mode 100644 index 0000000..9c1da9f --- /dev/null +++ b/test/grammar/cosmetic/scriptlet.test.ts @@ -0,0 +1,115 @@ +/** + * @file Tests for scriptlets rules + */ + +import { type AdblockTokenizer, getAdblockTokenizer } from '../common/get-adblock-tokenizer'; +import { expectTokens } from '../common/token-expectation'; + +let tokenize: AdblockTokenizer; + +// Before running any tests, we should load the grammar and get the tokenizer +beforeAll(async () => { + tokenize = await getAdblockTokenizer(); +}); + +describe('scriptlet rules', () => { + describe('valid', () => { + test('blocking', () => { + // single quoted arguments + expectTokens( + tokenize, + "#%#//scriptlet('foo', 'bar')", + [ + { fragment: '#%#', scopes: ['text.adblock', 'keyword.control.adblock'] }, + { fragment: '//scriptlet', scopes: ['text.adblock', 'entity.name.function.adblock'] }, + { fragment: '(', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + { fragment: "'foo'", scopes: ['text.adblock', 'string.quoted.adblock'] }, + { fragment: ', ', scopes: ['text.adblock', 'keyword.operator.adblock'] }, + { fragment: "'bar'", scopes: ['text.adblock', 'string.quoted.adblock'] }, + { fragment: ')', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + ], + ); + + // double quoted arguments + expectTokens( + tokenize, + '#%#//scriptlet("foo", "bar")', + [ + { fragment: '#%#', scopes: ['text.adblock', 'keyword.control.adblock'] }, + { fragment: '//scriptlet', scopes: ['text.adblock', 'entity.name.function.adblock'] }, + { fragment: '(', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + { fragment: '"foo"', scopes: ['text.adblock', 'string.quoted.adblock'] }, + { fragment: ', ', scopes: ['text.adblock', 'keyword.operator.adblock'] }, + { fragment: '"bar"', scopes: ['text.adblock', 'string.quoted.adblock'] }, + { fragment: ')', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + ], + ); + + // should handle if the argument contain a different quote type + expectTokens( + tokenize, + '#%#//scriptlet("foo\'bar")', + [ + { fragment: '#%#', scopes: ['text.adblock', 'keyword.control.adblock'] }, + { fragment: '//scriptlet', scopes: ['text.adblock', 'entity.name.function.adblock'] }, + { fragment: '(', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + { fragment: '"foo\'bar"', scopes: ['text.adblock', 'string.quoted.adblock'] }, + { fragment: ')', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + ], + ); + }); + + test('exception for specific scriptlet', () => { + expectTokens( + tokenize, + "#@%#//scriptlet('foo')", + [ + { fragment: '#@%#', scopes: ['text.adblock', 'keyword.control.adblock'] }, + { fragment: '//scriptlet', scopes: ['text.adblock', 'entity.name.function.adblock'] }, + { fragment: '(', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + { fragment: "'foo'", scopes: ['text.adblock', 'string.quoted.adblock'] }, + { fragment: ')', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + ], + ); + }); + + test('exception for all scriptlets', () => { + expectTokens( + tokenize, + '#@%#//scriptlet()', + [ + { fragment: '#@%#', scopes: ['text.adblock', 'keyword.control.adblock'] }, + { fragment: '//scriptlet', scopes: ['text.adblock', 'entity.name.function.adblock'] }, + { fragment: '(', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + { fragment: ')', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + ], + ); + + expectTokens( + tokenize, + '#@%#//scriptlet( )', + [ + { fragment: '#@%#', scopes: ['text.adblock', 'keyword.control.adblock'] }, + { fragment: '//scriptlet', scopes: ['text.adblock', 'entity.name.function.adblock'] }, + { fragment: '(', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + { fragment: ' ', scopes: ['text.adblock', 'entity.name.section.adblock.empty-scriptlet'] }, + { fragment: ')', scopes: ['text.adblock', 'punctuation.section.adblock'] }, + ], + ); + }); + }); + + describe('invalid', () => { + test('blocking', () => { + expectTokens( + tokenize, + // blocking scriptlet rule cannot be used without any arguments + '#%#//scriptlet()', + [ + { fragment: '#%#', scopes: ['text.adblock', 'keyword.control.adblock'] }, + { fragment: '//scriptlet()', scopes: ['text.adblock', 'invalid.illegal'] }, + ], + ); + }); + }); +}); diff --git a/test/static/rules/test_rules.txt b/test/static/rules/test_rules.txt index 2bcbeee..05a062c 100644 --- a/test/static/rules/test_rules.txt +++ b/test/static/rules/test_rules.txt @@ -440,3 +440,11 @@ example.com##.ads ! https://github.com/AdguardTeam/VscodeAdblockSyntax/issues/119 #@#+js(ubo-scriptlet0, arg0, arg1, arg2) example.com#@$#abp-snippet0 arg0 arg1 arg2 + +! https://github.com/AdguardTeam/VscodeAdblockSyntax/issues/132 +! empty blocking rule should be invalid +#%#//scriptlet() +#%#//scriptlet( ) +! empty exception rule should be valid +#@%#//scriptlet() +#@%#//scriptlet( ) diff --git a/yarn.lock b/yarn.lock index 95847fd..eef1a74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5593,10 +5593,10 @@ vfile@^6.0.0: unist-util-stringify-position "^4.0.0" vfile-message "^4.0.0" -vscode-oniguruma@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" - integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== +vscode-oniguruma@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-2.0.1.tgz#1196a343635ff8d42eb880e325b5f4e70731c02f" + integrity sha512-poJU8iHIWnC3vgphJnrLZyI3YdqRlR27xzqDmpPXYzA93R4Gk8z7T6oqDzDoHjoikA2aS82crdXFkjELCdJsjQ== vscode-textmate@^9.0.0: version "9.0.0"