Przeglądaj źródła

fix: bump minimum Chrome version to 61

* 61: URLSearchParams(obj)
* 61: scrollIntoView({ behavior: 'smooth' })
* 60: {...spreadOrRest}
* 60: CSS :focus-within
tophf 2 lat temu
rodzic
commit
586ba5871d

+ 1 - 1
.browserslistrc

@@ -1,2 +1,2 @@
-Chrome >= 57
+Chrome >= 61
 Firefox >= 57

+ 2 - 0
babel.config.js

@@ -6,6 +6,8 @@ module.exports = {
         modules: false,
       },
       useBuiltIns: false,
+      bugfixes: true,
+      // debug: true,
       loose: true,
     }],
   ],

+ 0 - 4
scripts/webpack-util.js

@@ -22,10 +22,6 @@ exports.restrictedSyntax = (
     Object.defineProperty(r, 'code', { enumerable: false, value: r.code })
   ))
 )([{
-  selector: 'ObjectExpression > SpreadElement',
-  message: 'Object spread adds a polyfill in injected* even if unused by it',
-  code: 'open({...{foo:1}})',
-}, {
   selector: 'ArrayPattern',
   message: 'Destructuring via Symbol.iterator may be spoofed/broken in an unsafe environment',
   code: '[window.foo]=[]',

+ 1 - 2
src/background/sync/dropbox.js

@@ -1,6 +1,5 @@
-import { getUniqId } from '@/common';
+import { dumpQuery, getUniqId, loadQuery } from '@/common';
 import { FORM_URLENCODED } from '@/common/consts';
-import { loadQuery, dumpQuery } from '../utils';
 import {
   getURI, getItemFilename, BaseService, isScriptFile, register,
   openAuthPage,

+ 1 - 2
src/background/sync/googledrive.js

@@ -1,10 +1,9 @@
 // Reference:
 // - https://developers.google.com/identity/protocols/oauth2/native-app
 // - https://developers.google.com/drive/v3/reference/files
-import { getUniqId, noop } from '@/common';
+import { dumpQuery, getUniqId, loadQuery, noop } from '@/common';
 import { CHARSET_UTF8, FORM_URLENCODED } from '@/common/consts';
 import { objectGet } from '@/common/object';
-import { loadQuery, dumpQuery } from '../utils';
 import {
   getURI, getItemFilename, BaseService, register, isScriptFile,
   openAuthPage,

+ 1 - 2
src/background/sync/onedrive.js

@@ -1,8 +1,7 @@
 // Reference: https://dev.onedrive.com/README.htm
-import { noop } from '@/common';
+import { dumpQuery, noop } from '@/common';
 import { FORM_URLENCODED } from '@/common/consts';
 import { objectGet } from '@/common/object';
-import { dumpQuery } from '../utils';
 import {
   getURI, getItemFilename, BaseService, isScriptFile, register,
   openAuthPage,

+ 1 - 1
src/background/utils/db.js

@@ -201,7 +201,7 @@ export async function normalizePosition() {
   return !!updates;
 }
 
-/** @return {Promise<number>} */
+/** @return {Promise<Boolean>} */
 export async function sortScripts() {
   aliveScripts.sort((a, b) => getInt(a.props.position) - getInt(b.props.position));
   const changed = await normalizePosition();

+ 0 - 1
src/background/utils/index.js

@@ -2,4 +2,3 @@ export { default as cache } from './cache';
 export { default as getEventEmitter } from './events';
 export * from './init';
 export * from './options';
-export * from './search';

+ 0 - 13
src/background/utils/search.js

@@ -1,13 +0,0 @@
-export function loadQuery(string) {
-  return string.split('&').reduce((data, piece) => {
-    const [key, val] = piece.split('=').map(decodeURIComponent);
-    data[key] = val;
-    return data;
-  }, {});
-}
-
-export function dumpQuery(dict) {
-  return Object.entries(dict)
-  .map(keyVal => keyVal.map(encodeURIComponent).join('='))
-  .join('&');
-}

+ 14 - 0
src/common/index.js

@@ -327,3 +327,17 @@ export async function makeRaw(response, noJoin) {
   const body = await blob2base64(response.data);
   return noJoin ? [type, body] : `${type},${body}`;
 }
+
+export function loadQuery(string) {
+  const res = {};
+  if (string) {
+    new URLSearchParams(string).forEach((val, key) => {
+      res[key] = val;
+    });
+  }
+  return res;
+}
+
+export function dumpQuery(dict) {
+  return `${new URLSearchParams(dict)}`;
+}

+ 16 - 17
src/common/router.js

@@ -1,24 +1,10 @@
 import { reactive } from 'vue';
+import { loadQuery } from '@/common';
 import { showConfirmation } from '@/common/ui';
 import { i18n } from './util';
 
-function parse(hash) {
-  const [pathname, search = ''] = hash.split('?');
-  const query = search.split('&').reduce((res, seq) => {
-    if (seq) {
-      const [key, val] = seq.split('=');
-      res[decodeURIComponent(key)] = decodeURIComponent(val);
-    }
-    return res;
-  }, {});
-  const paths = pathname.split('/');
-  return {
-    hash, pathname, paths, query,
-  };
-}
-
 const stack = [];
-export const route = reactive({});
+export const route = reactive(/** @type {VMRoute} */{});
 export const lastRoute = () => stack[stack.length - 1] || {};
 
 updateRoute();
@@ -26,7 +12,20 @@ updateRoute();
 function updateRoute(noConfirm) {
   const hash = window.location.hash.slice(1);
   if (noConfirm || !route.confirmChange) {
-    Object.assign(route, parse(hash));
+    const [pathname, search = ''] = hash.split('?');
+    /**
+     * @typedef {Object} VMRoute
+     * @prop {string} hash - entire hash without # e.g. 'path/name?foo=1&bar=2'
+     * @prop {string} pathname - 'path/name'
+     * @prop {string[]} paths - ['path', 'name']
+     * @prop {StringMap} query - {foo: '1', bar: '2'}
+     */
+    Object.assign(route, {
+      hash,
+      pathname,
+      paths: pathname.split('/'),
+      query: loadQuery(search),
+    });
   } else if (route.hash !== hash) {
     // restore the pinned route
     setRoute(route.hash, false, true);

+ 5 - 1
src/manifest.yml

@@ -51,7 +51,11 @@ commands:
   SkipScripts:
     description: __MSG_skipScripts__
 
-minimum_chrome_version: '57.0'
+minimum_chrome_version: '61.0'
+# 61: URLSearchParams(obj)
+# 61: scrollIntoView({ behavior: 'smooth' })
+# 60: {...spreadOrRest}
+# 60: CSS :focus-within
 
 browser_specific_settings:
   gecko:

+ 9 - 0
test/common/index.test.js

@@ -1,5 +1,6 @@
 import {
   isRemote, compareVersion, debounce, throttle,
+  loadQuery, dumpQuery,
 } from '@/common';
 
 jest.useFakeTimers();
@@ -146,3 +147,11 @@ test('throttle with invalid time', () => {
     expect(log).toEqual([0]);
   }
 });
+
+test('loadQuery/dumpQuery', () => {
+  const str = 'a=%7C%23%2C&b=&c';
+  const normalized = `${new URLSearchParams(str)}`;
+  const obj = loadQuery(str);
+  expect(obj).toEqual({ a: '|#,', b: '', c: '' });
+  expect(dumpQuery(obj)).toEqual(normalized);
+});