Просмотр исходного кода

feat: support domain, exclude-match, exclude rules for blacklists

close violentmonkey/violentmonkey#92
Gerald 8 лет назад
Родитель
Сommit
21ed040b44

+ 42 - 25
src/background/utils/tester.js

@@ -23,16 +23,18 @@ export function testGlob(url, rules) {
  * Test match rules like `@match` and `@exclude_match`.
  */
 export function testMatch(url, rules) {
-  const lifetime = 10 * 1000;
-  const key = `match:${url}`;
-  let matcher = cache.get(key);
-  if (matcher) {
-    cache.hit(key, lifetime);
-  } else {
-    matcher = matchTester(url);
-    cache.put(key, matcher, lifetime);
-  }
-  return rules.some(matcher);
+  const lifetime = 60 * 1000;
+  return rules.some(rule => {
+    const key = `match:${rule}`;
+    let matcher = cache.get(key);
+    if (matcher) {
+      cache.hit(key, lifetime);
+    } else {
+      matcher = matchTester(rule);
+      cache.put(key, matcher, lifetime);
+    }
+    return matcher.test(url);
+  });
 }
 
 export function testScript(url, script) {
@@ -97,28 +99,43 @@ function matchHost(rule, data) {
 function matchPath(rule, data) {
   return str2RE(rule).test(data);
 }
-function matchTester(url) {
-  const RE = /(.*?):\/\/([^/]*)\/(.*)/;
-  const urlParts = url.match(RE);
-  return str => {
-    if (str === '<all_urls>') return true;
-    const parts = str.match(RE);
-    return !!parts
-      && matchScheme(parts[1], urlParts[1])
-      && matchHost(parts[2], urlParts[2])
-      && matchPath(parts[3], urlParts[3]);
-  };
+function matchTester(rule) {
+  let test;
+  if (rule === '<all_urls>') test = () => true;
+  else {
+    const RE = /(.*?):\/\/([^/]*)\/(.*)/;
+    const ruleParts = rule.match(RE);
+    test = url => {
+      const parts = url.match(RE);
+      return !!ruleParts && !!parts
+      && matchScheme(ruleParts[1], parts[1])
+      && matchHost(ruleParts[2], parts[2])
+      && matchPath(ruleParts[3], parts[3]);
+    };
+  }
+  return { test };
 }
 
-let blacklistRE = [];
+let blacklistRules = [];
 resetBlacklist(getOption('blacklist'));
 hookOptions(changes => {
   const { blacklist } = changes;
   if (blacklist) resetBlacklist(blacklist);
 });
 export function testBlacklist(url) {
-  return blacklistRE.some(re => re.test(url));
+  return blacklistRules.some(re => re.test(url));
 }
-function resetBlacklist(list) {
-  blacklistRE = (list || []).map(rule => autoReg(rule));
+export function resetBlacklist(list) {
+  blacklistRules = (Array.isArray(list) ? list : (list || '').split('\n'))
+  .map(line => {
+    const item = line.trim();
+    if (!item || item.startsWith('#')) return;
+    // @exclude
+    if (item.startsWith('@exclude ')) return autoReg(item.slice(9));
+    // domains
+    if (item.indexOf('/') < 0) return matchTester(`*://${item}/*`);
+    // @exclude-match
+    return matchTester(item);
+  })
+  .filter(Boolean);
 }

+ 5 - 6
src/options/views/tab-settings/vm-blacklist.vue

@@ -16,17 +16,16 @@ import { showMessage } from '../../utils';
 
 export default {
   data() {
-    const rules = options.get('blacklist') || [];
+    let rules = options.get('blacklist');
+    // XXX compatible
+    if (Array.isArray(rules)) rules = rules.join('\n');
     return {
-      rules: rules.join('\n'),
+      rules,
     };
   },
   methods: {
     onSave() {
-      const rules = this.rules.split('\n')
-      .map(item => item.trim())
-      .filter(Boolean);
-      options.set('blacklist', rules);
+      options.set('blacklist', this.rules);
       showMessage({ text: i18n('msgSavedBlacklist') });
       sendMessage({ cmd: 'BlacklistReset' });
     },

+ 36 - 1
test/background/tester.js

@@ -1,5 +1,5 @@
 import test from 'tape';
-import { testScript } from 'src/background/utils/tester';
+import { testScript, testBlacklist, resetBlacklist } from 'src/background/utils/tester';
 import cache from 'src/background/utils/cache';
 
 test.onFinish(cache.destroy);
@@ -212,3 +212,38 @@ test('exclude-match', t => {
     q.end();
   });
 });
+
+test('blacklist', t => {
+  t.test('should exclude match rules', q => {
+    resetBlacklist(`\
+# match rules
+*://www.google.com/*
+`);
+    q.ok(testBlacklist('http://www.google.com/'));
+    q.ok(testBlacklist('https://www.google.com/'));
+    q.notOk(testBlacklist('https://twitter.com/'));
+    q.end();
+  });
+
+  t.test('should exclude domains', q => {
+    resetBlacklist(`\
+# domains
+www.google.com
+`);
+    q.ok(testBlacklist('http://www.google.com/'));
+    q.ok(testBlacklist('https://www.google.com/'));
+    q.notOk(testBlacklist('https://twitter.com/'));
+    q.end();
+  });
+
+  t.test('should support @exclude rules', q => {
+    resetBlacklist(`\
+# @exclude rules
+@exclude https://www.google.com/*
+`);
+    q.ok(testBlacklist('https://www.google.com/'));
+    q.ok(testBlacklist('https://www.google.com/whatever'));
+    q.notOk(testBlacklist('http://www.google.com/'));
+    q.end();
+  });
+});