瀏覽代碼

refactor: extract/split gmApi wrapper

tophf 4 年之前
父節點
當前提交
1e9a14d59e
共有 4 個文件被更改,包括 142 次插入139 次删除
  1. 135 0
      src/injected/web/gm-api-wrapper.js
  2. 5 137
      src/injected/web/gm-global-wrapper.js
  3. 1 1
      src/injected/web/index.js
  4. 1 1
      test/injected/gm-resource.test.js

+ 135 - 0
src/injected/web/gm-api-wrapper.js

@@ -0,0 +1,135 @@
+import bridge from './bridge';
+import { makeGmApi } from './gm-api';
+import { makeGlobalWrapper } from './gm-global-wrapper';
+import { makeComponentUtils, vmOwnFunc } from './util-web';
+import { createNullObj } from '../util';
+
+/** Name in Greasemonkey4 -> name in GM */
+const GM4_ALIAS = {
+  __proto__: null,
+  getResourceUrl: 'getResourceURL',
+  xmlHttpRequest: 'xmlhttpRequest',
+};
+const GM4_ASYNC = {
+  __proto__: null,
+  getResourceUrl: 1,
+  getValue: 1,
+  deleteValue: 1,
+  setValue: 1,
+  listValues: 1,
+};
+let gmApi;
+let componentUtils;
+
+export function makeGmApiWrapper(script) {
+  // Add GM functions
+  // Reference: http://wiki.greasespot.net/Greasemonkey_Manual:API
+  const { meta } = script;
+  const grant = meta.grant || [];
+  if (grant.length === 1 && grant[0] === 'none') {
+    grant.length = 0;
+  }
+  const { id } = script.props;
+  const resources = meta.resources || createNullObj();
+  /** @namespace VMInjectedScriptContext */
+  const context = {
+    id,
+    script,
+    resources,
+    dataKey: script.dataKey,
+    pathMap: script.custom.pathMap || createNullObj(),
+    urls: createNullObj(),
+  };
+  const gmInfo = makeGmInfo(script, resources);
+  const gm = {
+    __proto__: null,
+    GM: {
+      __proto__: null,
+      info: gmInfo,
+    },
+    GM_info: gmInfo,
+    unsafeWindow: global,
+  };
+  if (!componentUtils) {
+    componentUtils = makeComponentUtils();
+  }
+  assign(gm, componentUtils);
+  if (grant::indexOf('window.close') >= 0) {
+    gm.close = vmOwnFunc(() => bridge.post('TabClose', 0, context));
+  }
+  if (grant::indexOf('window.focus') >= 0) {
+    gm.focus = vmOwnFunc(() => bridge.post('TabFocus', 0, context));
+  }
+  if (!gmApi && grant.length) gmApi = makeGmApi();
+  grant::forEach((name) => {
+    // Spoofed String index getters won't be called within length, length itself is unforgeable
+    const gm4name = name.length > 3 && name[2] === '.' && name[0] === 'G' && name[1] === 'M'
+      && name::slice(3);
+    const fn = gmApi[gm4name ? `GM_${GM4_ALIAS[gm4name] || gm4name}` : name];
+    if (fn) {
+      if (gm4name) {
+        gm.GM[gm4name] = makeGmMethodCaller(fn, context, GM4_ASYNC[gm4name]);
+      } else {
+        gm[name] = makeGmMethodCaller(fn, context);
+      }
+    }
+  });
+  return grant.length ? makeGlobalWrapper(gm) : gm;
+}
+
+function makeGmInfo(script, resources) {
+  // TODO: move into background.js
+  const { meta } = script;
+  const metaCopy = createNullObj();
+  let val;
+  objectKeys(meta)::forEach((key) => {
+    val = meta[key];
+    switch (key) {
+    case 'match': // -> matches
+    case 'excludeMatch': // -> excludeMatches
+      key += 'e';
+      // fallthrough
+    case 'exclude': // -> excludes
+    case 'include': // -> includes
+      key += 's';
+      val = []::concat(val);
+      break;
+    default:
+    }
+    metaCopy[key] = val;
+  });
+  [
+    'description',
+    'name',
+    'namespace',
+    'runAt',
+    'version',
+  ]::forEach((key) => {
+    if (!metaCopy[key]) metaCopy[key] = '';
+  });
+  val = objectKeys(resources);
+  val::forEach((name, i) => {
+    val[i] = { name, url: resources[name] };
+  });
+  metaCopy.resources = val;
+  metaCopy.unwrap = false; // deprecated, always `false`
+  return {
+    uuid: script.props.uuid,
+    scriptMetaStr: script.metaStr,
+    scriptWillUpdate: !!script.config.shouldUpdate,
+    scriptHandler: 'Violentmonkey',
+    version: process.env.VM_VER,
+    injectInto: bridge.mode,
+    platform: assign({}, bridge.ua),
+    script: metaCopy,
+  };
+}
+
+function makeGmMethodCaller(gmMethod, context, isAsync) {
+  // keeping the native console.log intact
+  return gmMethod === gmApi.GM_log ? gmMethod : vmOwnFunc(
+    isAsync
+      ? (async (...args) => gmMethod::apply(context, args))
+      : gmMethod::bind(context),
+  );
+}

+ 5 - 137
src/injected/web/gm-wrapper.js → src/injected/web/gm-global-wrapper.js

@@ -1,139 +1,13 @@
 import { isFunction } from '#/common';
 import { INJECT_CONTENT } from '#/common/consts';
 import bridge from './bridge';
-import { makeGmApi } from './gm-api';
-import { FastLookup, makeComponentUtils, vmOwnFunc } from './util-web';
+import { FastLookup, vmOwnFunc } from './util-web';
 import { createNullObj, safePush } from '../util';
 
-/** Name in Greasemonkey4 -> name in GM */
-const GM4_ALIAS = {
-  __proto__: null,
-  getResourceUrl: 'getResourceURL',
-  xmlHttpRequest: 'xmlhttpRequest',
-};
-const GM4_ASYNC = {
-  __proto__: null,
-  getResourceUrl: 1,
-  getValue: 1,
-  deleteValue: 1,
-  setValue: 1,
-  listValues: 1,
-};
-let gmApi;
-let componentUtils;
-
-export function makeGmApiWrapper(script) {
-  // Add GM functions
-  // Reference: http://wiki.greasespot.net/Greasemonkey_Manual:API
-  const { meta } = script;
-  const grant = meta.grant || [];
-  if (grant.length === 1 && grant[0] === 'none') {
-    grant.length = 0;
-  }
-  const { id } = script.props;
-  const resources = meta.resources || createNullObj();
-  /** @namespace VMInjectedScriptContext */
-  const context = {
-    id,
-    script,
-    resources,
-    dataKey: script.dataKey,
-    pathMap: script.custom.pathMap || createNullObj(),
-    urls: createNullObj(),
-  };
-  const gmInfo = makeGmInfo(script, resources);
-  const gm = {
-    __proto__: null,
-    GM: {
-      __proto__: null,
-      info: gmInfo,
-    },
-    GM_info: gmInfo,
-    unsafeWindow: global,
-  };
-  if (!componentUtils) {
-    componentUtils = makeComponentUtils();
-  }
-  assign(gm, componentUtils);
-  if (grant::indexOf('window.close') >= 0) {
-    gm.close = vmOwnFunc(() => bridge.post('TabClose', 0, context));
-  }
-  if (grant::indexOf('window.focus') >= 0) {
-    gm.focus = vmOwnFunc(() => bridge.post('TabFocus', 0, context));
-  }
-  if (!gmApi && grant.length) gmApi = makeGmApi();
-  grant::forEach((name) => {
-    // Spoofed String index getters won't be called within length, length itself is unforgeable
-    const gm4name = name.length > 3 && name[2] === '.' && name[0] === 'G' && name[1] === 'M'
-      && name::slice(3);
-    const fn = gmApi[gm4name ? `GM_${GM4_ALIAS[gm4name] || gm4name}` : name];
-    if (fn) {
-      if (gm4name) {
-        gm.GM[gm4name] = makeGmMethodCaller(fn, context, GM4_ASYNC[gm4name]);
-      } else {
-        gm[name] = makeGmMethodCaller(fn, context);
-      }
-    }
-  });
-  return grant.length ? makeGlobalWrapper(gm) : gm;
-}
-
-function makeGmInfo(script, resources) {
-  // TODO: move into background.js
-  const { meta } = script;
-  const metaCopy = createNullObj();
-  let val;
-  objectKeys(meta)::forEach((key) => {
-    val = meta[key];
-    switch (key) {
-    case 'match': // -> matches
-    case 'excludeMatch': // -> excludeMatches
-      key += 'e';
-      // fallthrough
-    case 'exclude': // -> excludes
-    case 'include': // -> includes
-      key += 's';
-      val = []::concat(val);
-      break;
-    default:
-    }
-    metaCopy[key] = val;
-  });
-  [
-    'description',
-    'name',
-    'namespace',
-    'runAt',
-    'version',
-  ]::forEach((key) => {
-    if (!metaCopy[key]) metaCopy[key] = '';
-  });
-  val = objectKeys(resources);
-  val::forEach((name, i) => {
-    val[i] = { name, url: resources[name] };
-  });
-  metaCopy.resources = val;
-  metaCopy.unwrap = false; // deprecated, always `false`
-  return {
-    uuid: script.props.uuid,
-    scriptMetaStr: script.metaStr,
-    scriptWillUpdate: !!script.config.shouldUpdate,
-    scriptHandler: 'Violentmonkey',
-    version: process.env.VM_VER,
-    injectInto: bridge.mode,
-    platform: assign({}, bridge.ua),
-    script: metaCopy,
-  };
-}
-
-function makeGmMethodCaller(gmMethod, context, isAsync) {
-  // keeping the native console.log intact
-  return gmMethod === gmApi.GM_log ? gmMethod : vmOwnFunc(
-    isAsync
-      ? (async (...args) => gmMethod::apply(context, args))
-      : gmMethod::bind(context),
-  );
-}
+/** The index strings that look exactly like integers can't be forged
+ * but for example '011' doesn't look like 11 so it's allowed */
+const isFrameIndex = (key, isString) => isString
+  && key >= 0 && key <= 0xFFFF_FFFE && key === `${+key}`;
 
 const globalKeysSet = FastLookup();
 const globalKeys = (function makeGlobalKeys() {
@@ -425,12 +299,6 @@ function setEventHandler(name, value, globals, events) {
   }
 }
 
-/** The index strings that look exactly like integers can't be forged
- * but for example '011' doesn't look like 11 so it's allowed */
-function isFrameIndex(key, isString) {
-  return isString && key >= 0 && key <= 0xFFFF_FFFE && key === `${+key}`;
-}
-
 /** @this {FastLookup|Set} */
 function notIncludedIn(key) {
   return !this.has(key);

+ 1 - 1
src/injected/web/index.js

@@ -6,7 +6,7 @@ import './gm-values';
 import './notifications';
 import './requests';
 import './tabs';
-import { makeGmApiWrapper } from './gm-wrapper';
+import { makeGmApiWrapper } from './gm-api-wrapper';
 
 // Make sure to call safe::methods() in code that may run after userscripts
 

+ 1 - 1
test/injected/gm-resource.test.js

@@ -1,6 +1,6 @@
 import test from 'tape';
 import { buffer2string } from '#/common';
-import { makeGmApiWrapper } from '#/injected/web/gm-wrapper';
+import { makeGmApiWrapper } from '#/injected/web/gm-api-wrapper';
 import bridge from '#/injected/web/bridge';
 
 const stringAsBase64 = str => btoa(buffer2string(new TextEncoder().encode(str).buffer));