diff --git a/.gitignore b/.gitignore index 0a6c392f..ded7b2f9 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ dist dist-ssr build built -*.local # Logs logs @@ -47,5 +46,9 @@ xcuserdata/ *.xcuserstate *.dev.xcconfig XCBuildData -xcode/**/build/ -xcode/**/dist/ \ No newline at end of file +xcode/Ext-Safari/Resources/ + +# directories and files +local +*.local +/scripts/*.local.js \ No newline at end of file diff --git a/.prettierignore b/.prettierignore index be1335e6..5c1a0da1 100644 --- a/.prettierignore +++ b/.prettierignore @@ -6,7 +6,7 @@ # root /package -/public +/public/**/vendor /etc # dir diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 9d6aec0f..c967bcab 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -23,33 +23,86 @@ } }, { - "label": "npm: build", + "label": "npm: dev ext-safari-mac", + "detail": "Run dev server and build dev resource to xcode dist", + "type": "shell", + "command": "npm run dev:ext-safari-mac", + "group": "build", + "options": { + "cwd": "./" + } + }, + { + "label": "npm: dev ext-safari-ios", + "detail": "Run dev server and build dev resource to xcode dist", + "type": "shell", + "command": "npm run dev:ext-safari-ios", + "group": "build", + "options": { + "cwd": "./" + } + }, + { + "label": "npm: build mac", "detail": "Build to xcode dist path", "type": "shell", - "command": "npm run build", + "command": "npm run build:mac", "group": "build", "options": { "cwd": "./" } }, { - "label": "xcode: build", - "detail": "xcodebuild", + "label": "npm: build ios", + "detail": "Build to xcode dist path", "type": "shell", - "command": "xcodebuild -scheme Userscripts build", + "command": "npm run build:ios", + "group": "build", + "options": { + "cwd": "./" + } + }, + { + "label": "xcodebuild: mac-debug", + "detail": "xcodebuild mac debug", + "type": "shell", + "command": "xcodebuild -scheme Mac -configuration Debug", + "group": "build", + "options": { + "cwd": "./xcode/" + } + }, + { + "label": "xcodebuild: mac-vite", + "detail": "xcodebuild mac vite", + "type": "shell", + "command": "xcodebuild -scheme Mac-Vite-Dev -configuration Vite", "group": "build", "options": { "cwd": "./xcode/" } }, { - "label": "build all", - "detail": "npm build + xcodebuild", + "label": "dev: ext-safari-mac", + "detail": "npm: dev ext-safari-mac + xcodebuild: mac-vite", + "presentation": { + "reveal": "silent" + }, + "dependsOrder": "sequence", + "dependsOn": ["npm: dev ext-safari-mac", "xcodebuild: mac-vite"], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "build: mac debug", + "detail": "npm: build mac + xcodebuild: mac-debug", "presentation": { "reveal": "silent" }, "dependsOrder": "sequence", - "dependsOn": ["npm: build", "xcode: build"], + "dependsOn": ["npm: build mac", "xcodebuild: mac-debug"], "group": { "kind": "build", "isDefault": true diff --git a/docs/dev.md b/docs/dev.md index d1e7a7da..85633998 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -25,17 +25,18 @@ Reviewing the template will help you understand the composition of the project. # Dev -- `npm install`[^1] -- `npm run dev`[^1] +- `npm install` [^1] +- `npm run dev` [^1] # Build -- `npm run build`[^1] +- `npm run build:mac` [^1][^2] - `cd ./xcode` -- `xcodebuild`[^1][^2] or build with `Xcode` App +- `xcodebuild -scheme Mac` [^1][^2][^3] or build with `Xcode` App [^1]: These commands can also be executed directly through the vscode tasks. Please refer to: [/.vscode/tasks.json](../.vscode/tasks.json) -[^2]: Local setup may be required. Please refer to: [Building from the Command Line with Xcode FAQ](https://developer.apple.com/library/archive/technotes/tn2339/_index.html) +[^2]: Select the corresponding target and platform to build. Please refer to: [/package.json](../package.json) and [xcode-schemes](../xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/) +[^3]: Local setup may be required. Please refer to: [Building from the Command Line with Xcode FAQ](https://developer.apple.com/library/archive/technotes/tn2339/_index.html) # Xcode diff --git a/entry-ext-background.html b/entry-ext-background.html new file mode 100644 index 00000000..e3ee5d4c --- /dev/null +++ b/entry-ext-background.html @@ -0,0 +1,9 @@ + + + + Userscripts background + + + + + diff --git a/entry-ext-extension-page.html b/entry-ext-extension-page.html index 16e4944d..b112106c 100644 --- a/entry-ext-extension-page.html +++ b/entry-ext-extension-page.html @@ -10,6 +10,6 @@
- + diff --git a/eslint.config.js b/eslint.config.js index e2bd75e7..8bf9c246 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -14,13 +14,17 @@ import prettier from "eslint-config-prettier"; import globals from "globals"; export default [ - // https://eslint.org/docs/latest/use/configure/configuration-files-new#using-predefined-configurations - // https://github.com/eslint/eslint/tree/main/packages/js + /** + * @see {@link https://eslint.org/docs/latest/use/configure/configuration-files-new#using-predefined-configurations} + * @see {@link https://github.com/eslint/eslint/tree/main/packages/js} + */ js.configs.recommended, - // https://github.com/sveltejs/eslint-plugin-svelte - // currently no official svelte/recommended flat config - // flatten and call it through a custom config object + /** + * @see {@link https://github.com/sveltejs/eslint-plugin-svelte} + * currently no official svelte/recommended flat config + * flatten and call it through a custom config object + */ { files: ["**/*.svelte"], languageOptions: { @@ -36,20 +40,38 @@ export default [ }, }, - // https://github.com/prettier/eslint-config-prettier - // turns off the conflict rules, put it last + /** + * @see {@link https://github.com/prettier/eslint-config-prettier} + * turns off the conflict rules, put it last + */ prettier, - // custom config objects + /** custom config objects */ - // https://eslint.org/docs/latest/use/configure/configuration-files-new#globally-ignoring-files-with-ignores + /** @see {@link https://eslint.org/docs/latest/use/configure/configuration-files-new#globally-ignoring-files-with-ignores} */ { ignores: ["**/dist/", "**/build/", "etc/", "xcode/", "public/"], }, - // https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options + /** @see {@link https://eslint.org/docs/latest/use/configure/migration-guide#configuring-language-options} */ { - files: ["src/**/*.{js,svelte}"], + files: ["scripts/**/*.js"], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, + { + files: ["src/{app,dev}/**/*.{js,svelte}"], + languageOptions: { + globals: { + ...globals.browser, + }, + }, + }, + { + files: ["src/ext/**/*.{js,svelte}"], languageOptions: { globals: { ...globals.browser, diff --git a/package.json b/package.json index c2802776..36940a00 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,18 @@ "name": "userscripts", "private": true, "type": "module", + "sideEffects": false, "scripts": { "dev": "vite", - "build": "npm run build:app && npm run build:ext", + "dev:ext-safari-mac": "SAFARI_PLATFORM=mac node scripts/dev-ext-safari.js", + "dev:ext-safari-ios": "SAFARI_PLATFORM=ios node scripts/dev-ext-safari.js", + "build:mac": "npm run build:app && npm run build:ext-safari-mac", + "build:ios": "npm run build:app && npm run build:ext-safari-ios", "build:app": "node scripts/build-app.js", - "build:ext": "node scripts/build-ext-v4.js", + "build:ext-safari-mac": "SAFARI_PLATFORM=mac node scripts/build-ext-safari-15.js", + "build:ext-safari-ios": "SAFARI_PLATFORM=ios node scripts/build-ext-safari-15.js", + "build:ext-safari-mac-16.4": "SAFARI_PLATFORM=mac node scripts/build-ext-safari-16.4.js", + "build:ext-safari-ios-16.4": "SAFARI_PLATFORM=ios node scripts/build-ext-safari-16.4.js", "lint:js": "eslint . && prettier --check . --plugin prettier-plugin-svelte", "lint:css": "stylelint '**/*.{css,html,svelte}'", "prettier": "prettier --write . --plugin prettier-plugin-svelte" diff --git a/xcode/Ext-Safari/Resources/images/icon-128.png b/public/ext/safari-15/images/icon-128.png similarity index 100% rename from xcode/Ext-Safari/Resources/images/icon-128.png rename to public/ext/safari-15/images/icon-128.png diff --git a/xcode/Ext-Safari/Resources/images/icon-256.png b/public/ext/safari-15/images/icon-256.png similarity index 100% rename from xcode/Ext-Safari/Resources/images/icon-256.png rename to public/ext/safari-15/images/icon-256.png diff --git a/xcode/Ext-Safari/Resources/images/icon-48.png b/public/ext/safari-15/images/icon-48.png similarity index 100% rename from xcode/Ext-Safari/Resources/images/icon-48.png rename to public/ext/safari-15/images/icon-48.png diff --git a/xcode/Ext-Safari/Resources/images/icon-512.png b/public/ext/safari-15/images/icon-512.png similarity index 100% rename from xcode/Ext-Safari/Resources/images/icon-512.png rename to public/ext/safari-15/images/icon-512.png diff --git a/xcode/Ext-Safari/Resources/images/icon-96.png b/public/ext/safari-15/images/icon-96.png similarity index 100% rename from xcode/Ext-Safari/Resources/images/icon-96.png rename to public/ext/safari-15/images/icon-96.png diff --git a/xcode/Ext-Safari/Resources/images/toolbar-icon-16.png b/public/ext/safari-15/images/toolbar-icon-16.png similarity index 100% rename from xcode/Ext-Safari/Resources/images/toolbar-icon-16.png rename to public/ext/safari-15/images/toolbar-icon-16.png diff --git a/xcode/Ext-Safari/Resources/images/toolbar-icon-32.png b/public/ext/safari-15/images/toolbar-icon-32.png similarity index 100% rename from xcode/Ext-Safari/Resources/images/toolbar-icon-32.png rename to public/ext/safari-15/images/toolbar-icon-32.png diff --git a/public/ext/safari-15/manifest.json b/public/ext/safari-15/manifest.json new file mode 100644 index 00000000..99c503ee --- /dev/null +++ b/public/ext/safari-15/manifest.json @@ -0,0 +1,63 @@ +{ + "manifest_version": 2, + "default_locale": "en", + "name": "__MSG_extension_name__", + "description": "__MSG_extension_description__", + "version": "_VERSION_", + "icons": { + "48": "images/icon-48.png", + "96": "images/icon-96.png", + "128": "images/icon-128.png", + "256": "images/icon-256.png", + "512": "images/icon-512.png" + }, + "background": { + "scripts": ["dist/background.js"], + "persistent": false + }, + "browser_action": { + "default_popup": "dist/entry-ext-action-popup.html", + "default_icon": { + "16": "images/toolbar-icon-16.png", + "32": "images/toolbar-icon-32.png" + } + }, + "content_scripts": [ + { + "js": ["dist/content-scripts/userscripts.js"], + "matches": [""], + "run_at": "document_start", + "all_frames": true + }, + { + "js": ["dist/content-scripts/dot-user-js.js"], + "matches": [ + "*://*/*.user.js", + "*://*/*.user.js?*", + "*://*/*.user.css", + "*://*/*.user.css?*" + ], + "run_at": "document_start", + "all_frames": false + }, + { + "js": ["dist/content-scripts/greasyfork.js"], + "matches": ["*://*.greasyfork.org/*"], + "run_at": "document_start", + "all_frames": false + } + ], + "permissions": [ + "", + "clipboardWrite", + "contextMenus", + "declarativeNetRequest", + "declarativeNetRequestWithHostAccess", + "menus", + "nativeMessaging", + "storage", + "tabs", + "unlimitedStorage", + "webNavigation" + ] +} diff --git a/public/ext/safari-16.4/images/128.svg b/public/ext/safari-16.4/images/128.svg new file mode 100644 index 00000000..c6ec62ad --- /dev/null +++ b/public/ext/safari-16.4/images/128.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/ext/safari-16.4/images/action.svg b/public/ext/safari-16.4/images/action.svg new file mode 100644 index 00000000..ad16f09d --- /dev/null +++ b/public/ext/safari-16.4/images/action.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/ext/safari-16.4/manifest.json b/public/ext/safari-16.4/manifest.json new file mode 100644 index 00000000..7d2c00da --- /dev/null +++ b/public/ext/safari-16.4/manifest.json @@ -0,0 +1,48 @@ +{ + "manifest_version": 2, + "default_locale": "en", + "name": "__MSG_extension_name__", + "description": "__MSG_extension_description__", + "version": "_VERSION_", + "icons": { + "48": "images/128.svg", + "96": "images/128.svg", + "128": "images/128.svg", + "256": "images/128.svg", + "512": "images/128.svg" + }, + "background": { + "scripts": ["dist/background.js"], + "persistent": false + }, + "browser_action": { + "default_popup": "dist/entry-ext-action-popup.html", + "default_icon": "images/action.svg" + }, + "content_scripts": [ + { + "js": ["dist/content-scripts/userscripts.js"], + "matches": [""], + "run_at": "document_start", + "all_frames": true + } + ], + "permissions": [ + "", + "clipboardWrite", + "contextMenus", + "declarativeNetRequestWithHostAccess", + "menus", + "nativeMessaging", + "scripting", + "storage", + "tabs", + "unlimitedStorage", + "webNavigation" + ], + "browser_specific_settings": { + "safari": { + "strict_min_version": "16.4" + } + } +} diff --git a/public/ext/safari-dev/manifest-ios.json b/public/ext/safari-dev/manifest-ios.json new file mode 100644 index 00000000..2cb0308a --- /dev/null +++ b/public/ext/safari-dev/manifest-ios.json @@ -0,0 +1,52 @@ +{ + "manifest_version": 2, + "default_locale": "en", + "name": "__MSG_extension_name__", + "description": "__MSG_extension_description__", + "version": "_VERSION_", + "icons": { + "48": "images/128.svg", + "96": "images/128.svg", + "128": "images/128.svg", + "256": "images/128.svg", + "512": "images/128.svg" + }, + "background": { + "page": "dist/entry-ext-background.html", + "persistent": false + }, + "browser_action": { + "default_popup": "dist/entry-ext-action-popup.html", + "default_icon": "images/action.svg" + }, + "options_ui": { + "page": "dist/entry-ext-extension-page.html#settings" + }, + "content_scripts": [ + { + "js": ["dist/content-scripts/userscripts.js"], + "matches": [""], + "run_at": "document_start", + "all_frames": true + } + ], + "permissions": [ + "", + "clipboardWrite", + "contextMenus", + "declarativeNetRequestWithHostAccess", + "menus", + "nativeMessaging", + "scripting", + "storage", + "tabs", + "unlimitedStorage", + "webNavigation" + ], + "browser_specific_settings": { + "safari": { + "strict_min_version": "16.4" + } + }, + "content_security_policy": "script-src 'self' https://localhost:55173 https://userscripts.test:55173" +} diff --git a/public/ext/safari-dev/manifest-mac.json b/public/ext/safari-dev/manifest-mac.json new file mode 100644 index 00000000..046f8239 --- /dev/null +++ b/public/ext/safari-dev/manifest-mac.json @@ -0,0 +1,52 @@ +{ + "manifest_version": 2, + "default_locale": "en", + "name": "__MSG_extension_name__", + "description": "__MSG_extension_description__", + "version": "_VERSION_", + "icons": { + "48": "images/128.svg", + "96": "images/128.svg", + "128": "images/128.svg", + "256": "images/128.svg", + "512": "images/128.svg" + }, + "background": { + "page": "dist/entry-ext-background.html", + "persistent": true + }, + "browser_action": { + "default_popup": "dist/entry-ext-action-popup.html", + "default_icon": "images/action.svg" + }, + "options_ui": { + "page": "dist/entry-ext-extension-page.html#settings" + }, + "content_scripts": [ + { + "js": ["dist/content-scripts/userscripts.js"], + "matches": [""], + "run_at": "document_start", + "all_frames": true + } + ], + "permissions": [ + "", + "clipboardWrite", + "contextMenus", + "declarativeNetRequestWithHostAccess", + "menus", + "nativeMessaging", + "scripting", + "storage", + "tabs", + "unlimitedStorage", + "webNavigation" + ], + "browser_specific_settings": { + "safari": { + "strict_min_version": "16.4" + } + }, + "content_security_policy": "script-src 'self' https://localhost:55173 https://userscripts.test:55173" +} diff --git a/public/ext/shared-dev/images/128.svg b/public/ext/shared-dev/images/128.svg new file mode 100644 index 00000000..76189438 --- /dev/null +++ b/public/ext/shared-dev/images/128.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/ext/shared-dev/images/action.svg b/public/ext/shared-dev/images/action.svg new file mode 100644 index 00000000..3789dd89 --- /dev/null +++ b/public/ext/shared-dev/images/action.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/ext/shared/_locales/en/messages.json b/public/ext/shared/_locales/en/messages.json new file mode 100644 index 00000000..e840a3a2 --- /dev/null +++ b/public/ext/shared/_locales/en/messages.json @@ -0,0 +1,10 @@ +{ + "extension_name": { + "message": "_NAME_", + "description": "The display name for the extension." + }, + "extension_description": { + "message": "Save and run javascript for the web pages you visit", + "description": "Description of what the extension does." + } +} diff --git a/public/extension-page/jshint.min.js b/public/ext/vendor/jshint.min.js similarity index 100% rename from public/extension-page/jshint.min.js rename to public/ext/vendor/jshint.min.js diff --git a/scripts/build-app.js b/scripts/build-app.js index 2fedc7ce..f4713f70 100644 --- a/scripts/build-app.js +++ b/scripts/build-app.js @@ -14,6 +14,7 @@ import { svelte } from "@sveltejs/vite-plugin-svelte"; * Disable auto resolving {@link vite.config.js} * @see {@link https://vitejs.dev/config/ Config} * @see {@link https://vitejs.dev/guide/api-javascript.html#inlineconfig configFile} + * @type {import("vite").InlineConfig} */ const defineConfig = { base: "./", diff --git a/scripts/build-ext-v4.js b/scripts/build-ext-safari-15.js similarity index 54% rename from scripts/build-ext-v4.js rename to scripts/build-ext-safari-15.js index 03b01c3a..3242f700 100644 --- a/scripts/build-ext-v4.js +++ b/scripts/build-ext-safari-15.js @@ -16,16 +16,20 @@ import { build } from "vite"; import { svelte } from "@sveltejs/vite-plugin-svelte"; +import { cp, emptyBuildDir, rootDir, SAFARI_EXT_RESOURCES } from "./utils.js"; /** * Define default vite config options * Disable auto resolving {@link vite.config.js} * @see {@link https://vitejs.dev/config/ Config} - * @see {@link https://vitejs.dev/guide/api-javascript.html#inlineconfig configFile} + * @see {@link https://vitejs.dev/guide/api-javascript.html#inlineconfig InlineConfig} + * @type {import("vite").InlineConfig} */ const defineConfig = { - base: "./", configFile: false, + envFile: false, + root: await rootDir(), + base: "./", define: { "import.meta.env.BROWSER": JSON.stringify("safari"), "import.meta.env.NATIVE_APP": JSON.stringify("app"), @@ -33,41 +37,62 @@ const defineConfig = { }; /** - * Build shared modules for safari - * These multiple entry files will share the same modules - * Using a subdirectory avoid emptying other built files + * Empty resources directory + * Copy public static assets */ -build({ - ...defineConfig, - plugins: [svelte()], - build: { - outDir: "xcode/Ext-Safari/Resources/dist/s/", - rollupOptions: { - input: ["entry-ext-action-popup.html", "entry-ext-extension-page.html"], - }, - }, -}); +await emptyBuildDir(SAFARI_EXT_RESOURCES); +cp("public/ext/shared", SAFARI_EXT_RESOURCES); +cp("public/ext/safari-15", SAFARI_EXT_RESOURCES); -/** - * Build independent scripts for safari - * Each entry in the array will generate a separate script - */ +/** Build content scripts */ [ - { background: "src/ext/background/main.js" }, - { content: "src/ext/content-scripts/main.js" }, + { userscripts: "src/ext/content-scripts/entry-userscripts.js" }, + { "dot-user-js": "src/ext/content-scripts/entry-dot-user-js.js" }, + { greasyfork: "src/ext/content-scripts/entry-greasyfork.js" }, ].forEach((input) => { build({ ...defineConfig, build: { - outDir: "xcode/Ext-Safari/Resources/dist/", + outDir: `${SAFARI_EXT_RESOURCES}/dist/content-scripts/`, emptyOutDir: false, copyPublicDir: false, rollupOptions: { input, - output: { - entryFileNames: "[name].js", - }, + output: { entryFileNames: "[name].js" }, }, }, }); }); + +/** Build background scripts */ +build({ + ...defineConfig, + build: { + outDir: `${SAFARI_EXT_RESOURCES}/dist/`, + emptyOutDir: false, + copyPublicDir: false, + rollupOptions: { + input: { background: "src/ext/background/main.js" }, + output: { entryFileNames: "[name].js" }, + }, + }, +}); + +/** Build shared modules */ +/** @type {import("rollup").InputOption} */ +let input = ["entry-ext-action-popup.html", "entry-ext-extension-page.html"]; +if (process.env.SAFARI_PLATFORM === "ios") { + input = ["entry-ext-action-popup.html"]; +} +build({ + ...defineConfig, + plugins: [svelte()], + publicDir: "public/ext/vendor/", + build: { + outDir: `${SAFARI_EXT_RESOURCES}/dist/`, + emptyOutDir: false, + rollupOptions: { + input, + }, + }, +}); diff --git a/scripts/build-ext-safari-16.4.js b/scripts/build-ext-safari-16.4.js new file mode 100644 index 00000000..12a67481 --- /dev/null +++ b/scripts/build-ext-safari-16.4.js @@ -0,0 +1,106 @@ +/** + * @file Build Safari extension resources using the Vite JavaScript API + * @see {@link https://vitejs.dev/guide/api-javascript.html JavaScript API} + * + * Safari supports for modules in background since 16.4 + * @see {@link https://developer.apple.com/documentation/safari-release-notes/safari-16_4-release-notes#Safari-Extensions} + * @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background#browser_compatibility} + * + * Content scripts not support import modules, and due to their privileges and the + * speed of injecting user scripts, use a independent build currently + * + * All build processes start at the same time due to asynchronous calls + * The assets name is irrelevant, just need to determine the entry path + */ + +import { build } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; +import { cp, emptyBuildDir, rootDir, SAFARI_EXT_RESOURCES } from "./utils.js"; + +/** + * Define default vite config options + * Disable auto resolving {@link vite.config.js} + * @see {@link https://vitejs.dev/config/ Config} + * @see {@link https://vitejs.dev/guide/api-javascript.html#inlineconfig configFile} + * @type {import("vite").InlineConfig} + */ +const defineConfig = { + configFile: false, + envFile: false, + root: await rootDir(), + base: "./", + define: { + "import.meta.env.BROWSER": JSON.stringify("safari"), + "import.meta.env.NATIVE_APP": JSON.stringify("app"), + }, +}; + +/** + * Empty resources directory + * Copy public static assets + */ +await emptyBuildDir(SAFARI_EXT_RESOURCES); +cp("public/ext/shared", SAFARI_EXT_RESOURCES); +cp("public/ext/safari-16.4", SAFARI_EXT_RESOURCES); + +/** Build content scripts */ +[ + { userscripts: "src/ext/content-scripts/entry-userscripts.js" }, + { "dot-user-js": "src/ext/content-scripts/entry-dot-user-js.js" }, + { greasyfork: "src/ext/content-scripts/entry-greasyfork.js" }, +].forEach((input) => { + build({ + ...defineConfig, + build: { + outDir: `${SAFARI_EXT_RESOURCES}/dist/content-scripts/`, + emptyOutDir: false, + copyPublicDir: false, + rollupOptions: { + input, + output: { entryFileNames: "[name].js" }, + }, + }, + }); +}); + +/** + * Build background scripts + * Modular background may not load correctly on Safari startup + * Currently build classic script separately to avoid this error + */ +build({ + ...defineConfig, + build: { + outDir: `${SAFARI_EXT_RESOURCES}/dist/`, + emptyOutDir: false, + copyPublicDir: false, + rollupOptions: { + input: { background: "src/ext/background/main.js" }, + output: { entryFileNames: "[name].js" }, + }, + }, +}); + +/** Build shared modules */ +/** @type {import("rollup").InputOption} */ +let input = { + // background: "src/ext/background/main.js", + "action-popup": "entry-ext-action-popup.html", + "extension-page": "entry-ext-extension-page.html", +}; +if (process.env.SAFARI_PLATFORM === "ios") { + delete input["extension-page"]; +} +build({ + ...defineConfig, + plugins: [svelte()], + publicDir: "public/ext/vendor/", + build: { + outDir: `${SAFARI_EXT_RESOURCES}/dist/`, + emptyOutDir: false, + rollupOptions: { + input, + output: { entryFileNames: "[name].js" }, + }, + }, +}); diff --git a/scripts/build-ext-v5.js b/scripts/build-ext-v5.js deleted file mode 100644 index e810c972..00000000 --- a/scripts/build-ext-v5.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @file Build Safari extension resources using the Vite JavaScript API - * @see {@link https://vitejs.dev/guide/api-javascript.html JavaScript API} - * - * Safari supports for modules in background since 16.4 - * @see {@link https://developer.apple.com/documentation/safari-release-notes/safari-16_4-release-notes#Safari-Extensions} - * @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background#browser_compatibility} - * - * Content scripts not support import modules, and due to their privileges and the - * speed of injecting user scripts, use a independent build currently - * - * All build processes start at the same time due to asynchronous calls - * The assets name is irrelevant, just need to determine the entry path - */ - -import { build } from "vite"; -import { svelte } from "@sveltejs/vite-plugin-svelte"; - -/** - * Define default vite config options - * Disable auto resolving {@link vite.config.js} - * @see {@link https://vitejs.dev/config/ Config} - * @see {@link https://vitejs.dev/guide/api-javascript.html#inlineconfig configFile} - */ -const defineConfig = { - base: "./", - configFile: false, - define: { - "import.meta.env.BROWSER": JSON.stringify("safari"), - "import.meta.env.NATIVE_APP": JSON.stringify("app"), - }, -}; - -/** - * Build shared modules for safari - * These multiple entry files will share the same modules - * Using a subdirectory avoid emptying other built files - */ -build({ - ...defineConfig, - plugins: [svelte()], - build: { - outDir: "xcode/Ext-Safari/Resources/dist/s/", - rollupOptions: { - input: { - background: "src/ext/background/main.js", - "action-popup": "entry-ext-action-popup.html", - "extension-page": "entry-ext-extension-page.html", - }, - output: { - entryFileNames: "[name].js", - }, - }, - }, -}); - -/** - * Build independent scripts for safari - * Each entry in the array will generate a separate script - */ -[{ content: "src/ext/content-scripts/main.js" }].forEach((input) => { - build({ - ...defineConfig, - build: { - outDir: "xcode/Ext-Safari/Resources/dist/", - emptyOutDir: false, - copyPublicDir: false, - rollupOptions: { - input, - output: { - entryFileNames: "[name].js", - }, - }, - }, - }); -}); diff --git a/scripts/dev-ext-safari.js b/scripts/dev-ext-safari.js new file mode 100644 index 00000000..2b4e7c25 --- /dev/null +++ b/scripts/dev-ext-safari.js @@ -0,0 +1,220 @@ +/** + * @file Develop Safari extension resources using the Vite JavaScript API + * @see {@link https://vitejs.dev/guide/api-javascript.html JavaScript API} + * This development build and server requires a valid https certificate to support remote real-time development + * Typically using a self-signed certificate, it needs to be installed and trusted by the device or simulator + * @see {@link https://developer.apple.com/library/archive/qa/qa1948/} + * @see {@link https://developer.apple.com/library/archive/technotes/tn2326/} + */ + +import { build, createServer } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; +import { + cp, + emptyBuildDir, + sharedServerOptions, + rootDir, + SAFARI_EXT_RESOURCES, +} from "./utils.js"; +import https from "node:https"; + +/** + * Define default vite config options + * Disable auto resolving {@link vite.config.js} + * @see {@link https://vitejs.dev/config/ Config} + * @see {@link https://vitejs.dev/guide/api-javascript.html#inlineconfig configFile} + * @type {import("vite").InlineConfig} + */ +const defineConfig = { + configFile: false, + envFile: false, + root: await rootDir(), + base: "./", + define: { + "import.meta.env.BROWSER": JSON.stringify("safari"), + "import.meta.env.NATIVE_APP": JSON.stringify("app"), + }, +}; + +/** + * Build resources for remote real-time development + * @param {import("vite").ViteDevServer} server + * @param {string} origin + */ +async function buildResources(server, origin) { + /** + * empty resources directory + * copy public static assets + */ + await emptyBuildDir("dist"); + await emptyBuildDir(SAFARI_EXT_RESOURCES); + cp("public/ext/shared", SAFARI_EXT_RESOURCES); + cp("public/ext/shared-dev", SAFARI_EXT_RESOURCES); + if (process.env.SAFARI_PLATFORM === "ios") { + cp( + "public/ext/safari-dev/manifest-ios.json", + `${SAFARI_EXT_RESOURCES}/manifest.json`, + ); + } else { + cp( + "public/ext/safari-dev/manifest-mac.json", + `${SAFARI_EXT_RESOURCES}/manifest.json`, + ); + } + + /** build content scripts */ + [ + { userscripts: "src/ext/content-scripts/entry-userscripts.js" }, + { "dot-user-js": "src/ext/content-scripts/entry-dot-user-js.js" }, + { greasyfork: "src/ext/content-scripts/entry-greasyfork.js" }, + ].forEach((input) => { + /** build proxy content scripts replace actual code */ + build({ + ...defineConfig, + plugins: [ + { + name: "generate-content-proxy", + load(id) { + const name = id.replace(/.+entry-/, ""); + const url = `${origin}/dist/content-scripts/${name}`; + return `// proxy content + const xhr = new XMLHttpRequest(); + xhr.open("GET", "${url}", false); + xhr.send(); + const code = xhr.responseText; + try { + Function(code + "//# sourceURL=proxy-${name}")(); + } catch (error) { + console.error(error); + }`; + }, + }, + ], + build: { + outDir: `${SAFARI_EXT_RESOURCES}/dist/content-scripts/`, + emptyOutDir: false, + copyPublicDir: false, + rollupOptions: { + input, + output: { entryFileNames: "[name].js" }, + }, + }, + }); + /** build content scripts for dev server and watch changes */ + build({ + ...defineConfig, + build: { + outDir: `dist/content-scripts/`, + emptyOutDir: false, + copyPublicDir: false, + rollupOptions: { + input, + output: { entryFileNames: "[name].js" }, + }, + watch: {}, + minify: false, + }, + }); + }); + + /** generate entrance dist */ + build({ + ...defineConfig, + publicDir: "public/ext/vendor/", + plugins: [ + /** + * @see {@link https://github.com/vitejs/vite/issues/14263} + * Dev only requires entrances, so order `pre` without transform modules + */ + { + name: "generate-dev-entrance", + transformIndexHtml: { + order: "pre", + async handler(html, ctx) { + const str = await server.transformIndexHtml(ctx.path, html); + return str.replaceAll(`src="/`, `src="${origin}/`); + }, + }, + }, + ], + build: { + outDir: `${SAFARI_EXT_RESOURCES}/dist/`, + emptyOutDir: false, + rollupOptions: { + input: { + background: "entry-ext-background.html", + "action-popup": "entry-ext-action-popup.html", + "extension-page": "entry-ext-extension-page.html", + }, + }, + }, + }); +} + +/** + * Define shared constants + * Developing in native machine and simulator can just use `https://localhost:port/` as the origin + * But using a fixed domain name on non-native devices such as real iOS devices is a better choice + * The local domain name needs to be resolved to the LAN IP address on LAN DNS or the target device + * When the origin specified here is unreachable, localhost will be automatically used as the alternate + * The origin requires as an exemption to be added to the `manifest.json` due to default CSP limitations + * @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy} + * @see {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_security_policy} + */ +const serverOptions = await sharedServerOptions(); +const SERVER_PORT = 55173; +const SERVER_ORIGIN = `https://userscripts.test:${SERVER_PORT}`; + +/** + * Check if the server is reachable with self-signed certificate + * @param {string | URL} url + * @returns {Promise} + */ +async function serverCheck(url) { + const options = { + method: "HEAD", + ca: serverOptions.ca, + headers: { Accept: "*/*" }, + }; + return new Promise((resolve) => { + const req = https.request(url, options, (res) => { + if (res.headers.server === SERVER_ORIGIN) { + resolve(true); + } + resolve(false); + }); + req.on("error", (e) => { + console.error(`${req.host}: ${e.message}`); + resolve(false); + }); + req.end(); + }); +} + +/** main process */ +(async () => { + /** run development server */ + const server = await createServer({ + ...defineConfig, + plugins: [svelte()], + server: { + host: true, + port: SERVER_PORT, + strictPort: true, + https: { key: serverOptions.key, cert: serverOptions.cert }, + headers: { server: SERVER_ORIGIN }, + }, + }); + await server.listen(); + server.printUrls(); + + // Check available origins and build resources + for (let url of [SERVER_ORIGIN, ...server.resolvedUrls.local]) { + if (await serverCheck(url)) { + const origin = url.at(-1) === "/" ? url.slice(0, -1) : url; + console.info(`build with origin: ${origin}`); + buildResources(server, origin); + break; + } + } +})(); diff --git a/scripts/jsconfig.json b/scripts/jsconfig.json new file mode 100644 index 00000000..f0633242 --- /dev/null +++ b/scripts/jsconfig.json @@ -0,0 +1,26 @@ +// https://code.visualstudio.com/docs/languages/jsconfig +// https://www.typescriptlang.org/docs/handbook/tsconfig-json.html +// https://www.typescriptlang.org/tsconfig + +// https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html +// https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html + +{ + "compilerOptions": { + "target": "ESNext", + "module": "NodeNext", + "moduleResolution": "nodenext", + + "verbatimModuleSyntax": true, + "isolatedModules": true, + "resolveJsonModule": true, + + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "sourceMap": true + }, + "include": ["**/*.d.ts", "**/*.js"] +} diff --git a/scripts/preview-app.js b/scripts/preview-app.js index 691f601c..d9060d8d 100644 --- a/scripts/preview-app.js +++ b/scripts/preview-app.js @@ -10,6 +10,7 @@ import { preview } from "vite"; * Disable auto resolving {@link vite.config.js} * @see {@link https://vitejs.dev/config/ Config} * @see {@link https://vitejs.dev/guide/api-javascript.html#inlineconfig configFile} + * @type {import("vite").InlineConfig} */ const defineConfig = { base: "./", diff --git a/scripts/utils.js b/scripts/utils.js new file mode 100644 index 00000000..c80fb51b --- /dev/null +++ b/scripts/utils.js @@ -0,0 +1,92 @@ +import { chdir, cwd } from "node:process"; +import { fileURLToPath } from "node:url"; +import { + copyFile, + mkdir, + readdir, + readFile, + realpath, + rm, + stat, +} from "node:fs/promises"; + +/** Define shared constants */ +export const SAFARI_APP_RESOURCES = "xcode/App-Shared/Resources"; +export const SAFARI_EXT_RESOURCES = "xcode/Ext-Safari/Resources"; + +/** + * If not then cd to root dir and returns the path + * @returns {Promise} project root directory + */ +export async function rootDir() { + const root = fileURLToPath(new URL("..", import.meta.url)); + if (cwd() !== (await realpath(root))) { + chdir(root); + console.info("cd:", root); + } + return root; +} + +/** + * Empty the build directory safely + * @param {string} dir + * @returns {Promise} + */ +export async function emptyBuildDir(dir) { + const buildPaths = ["dist", SAFARI_APP_RESOURCES, SAFARI_EXT_RESOURCES]; + if (!buildPaths.includes(dir)) { + console.error("Non-build path, cannot be empty."); + return false; + } + const root = await rootDir(); + try { + for (const sub of await readdir(dir)) { + const path = `${root}/${dir}/${sub}`; + // console.log("rm:", path); // DEBUG + await rm(path, { force: true, recursive: true }); + } + return true; + } catch (error) { + console.error("emptyBuildDir:", error); + return false; + } +} + +/** + * Copy a file or folder recursively + * @param {string} src Source file or directory + * @param {string} dest Destination file or directory + */ +export async function cp(src, dest) { + // console.log("cp:", src, "->", dest); // DEBUG + await rootDir(); + const srcStat = await stat(src); + if (srcStat.isFile()) return copyFile(src, dest); + if (!srcStat.isDirectory()) return; + await mkdir(dest, { recursive: true }); + for (const sub of await readdir(src)) { + if ([".DS_Store"].includes(sub)) continue; + await cp(`${src}/${sub}`, `${dest}/${sub}`); + } +} + +/** + * Read file and return text + * @param {string} file file path + * @returns {Promise} file content + */ +export async function read(file) { + const path = fileURLToPath(new URL(file, import.meta.url)); + return readFile(path, "utf8"); +} + +/** + * @see {@link https://vitejs.dev/config/server-options.html#server-https} + * @see {@link https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener} + * @returns {Promise} https.ServerOptions + */ +export const sharedServerOptions = async () => ({ + ca: await read("./local/ca.pem"), + key: await read("./local/key.pem"), + cert: await read("./local/cert.pem"), +}); diff --git a/src/ext/action-popup/main.js b/src/ext/action-popup/main.js index ecf31c3f..2829a2c0 100644 --- a/src/ext/action-popup/main.js +++ b/src/ext/action-popup/main.js @@ -8,11 +8,12 @@ if (import.meta.env.MODE === "development") { const modules = import.meta.glob("../shared/dev.js", { eager: true }); const browser = modules["../shared/dev.js"]["browser"]; console.debug("DEV-ENV", import.meta.env, modules, browser); - // assign to window simulation WebExtension APIs - window.browser = browser; - // macos popup simulation - const style = document.createElement("style"); - style.textContent = ` + if (!window?.browser?.extension) { + // assign to window simulation WebExtension APIs + window.browser = browser; + // macos popup simulation + const style = document.createElement("style"); + style.textContent = ` body { top: 20px; left: 20px; @@ -32,7 +33,8 @@ body:before { border-radius: 9px; } `; - browser.platform === "macos" && document.head.append(style); + browser.platform === "macos" && document.head.append(style); + } } const app = new App({ diff --git a/src/ext/background/main.js b/src/ext/background/main.js index 5d481b2d..e0530cae 100644 --- a/src/ext/background/main.js +++ b/src/ext/background/main.js @@ -321,7 +321,7 @@ async function handleMessage(request, sender, sendResponse) { } case "API_ADD_STYLE": { const tabId = sender.tab.id; - /** @type {{code: string, cssOrigin: "user"|"author"}} */ + /** @type {import("webextension-polyfill").ExtensionTypes.InjectDetails} */ const details = { code: request.css, cssOrigin: "user" }; return browser.tabs.insertCSS(tabId, details); } diff --git a/src/ext/content-scripts/entry-dot-user-js.js b/src/ext/content-scripts/entry-dot-user-js.js new file mode 100644 index 00000000..e69de29b diff --git a/src/ext/content-scripts/entry-greasyfork.js b/src/ext/content-scripts/entry-greasyfork.js new file mode 100644 index 00000000..e69de29b diff --git a/src/ext/content-scripts/main.js b/src/ext/content-scripts/entry-userscripts.js similarity index 92% rename from src/ext/content-scripts/main.js rename to src/ext/content-scripts/entry-userscripts.js index ce307fd8..ab620622 100644 --- a/src/ext/content-scripts/main.js +++ b/src/ext/content-scripts/entry-userscripts.js @@ -1,4 +1,4 @@ -import apis from "./api.js"; +import USAPI from "./api.js"; // code received from background page will be stored in this variable // code referenced again when strict CSPs block initial injection attempt @@ -52,24 +52,26 @@ function injectJS(userscript) { if (injectInto === "auto" && (userscript.fallback || cspFallbackAttempted)) { injectInto = "content"; console.warn(`Attempting fallback injection for ${name}`); - } else if (window.self === window.top) { - console.info(`Injecting ${name} %c(js)`, "color: #fff600"); + } + const world = injectInto === "content" ? "content" : "page"; + if (window.self === window.top) { + console.info(`Injecting: ${name} %c(js/${world})`, "color: #fff600"); } else { console.info( - `Injecting ${name} %c(js)%c - %cframe(${label})(${window.location})`, + `Injecting: ${name} %c(js/${world})%c - %cframe(${label})(${window.location})`, "color: #fff600", "color: inherit", "color: #006fff", ); } - if (injectInto !== "content") { + if (world === "page") { const div = document.createElement("div"); div.style.display = "none"; const shadowRoot = div.attachShadow({ mode: "closed" }); - document.body.append(div); const tag = document.createElement("script"); tag.textContent = code; shadowRoot.append(tag); + (document.body ?? document.head ?? document.documentElement).append(div); } else { try { // eslint-disable-next-line no-new-func @@ -186,8 +188,8 @@ async function injection() { for (let j = 0; j < grants.length; j++) { const grant = grants[j]; const method = grant.split(".")[1] || grant.split(".")[0]; - // ensure API method exists in apis object - if (!Object.keys(apis).includes(method)) continue; + // ensure API method exists in USAPI object + if (!Object.keys(USAPI).includes(method)) continue; // add granted methods switch (method) { case "info": @@ -197,15 +199,15 @@ async function injection() { case "setValue": case "deleteValue": case "listValues": - userscript.apis.GM[method] = apis[method].bind({ + userscript.apis.GM[method] = USAPI[method].bind({ US_filename: filename, }); break; case "GM_xmlhttpRequest": - userscript.apis[method] = apis[method]; + userscript.apis[method] = USAPI[method]; break; default: - userscript.apis.GM[method] = apis[method]; + userscript.apis.GM[method] = USAPI[method]; } } // triage userjs item for injection diff --git a/src/ext/extension-page/main.js b/src/ext/extension-page/main.js index 9e90a4c7..ec2580e9 100644 --- a/src/ext/extension-page/main.js +++ b/src/ext/extension-page/main.js @@ -8,8 +8,10 @@ if (import.meta.env.MODE === "development") { const modules = import.meta.glob("../shared/dev.js", { eager: true }); const browser = modules["../shared/dev.js"]["browser"]; console.debug("DEV-ENV", import.meta.env, modules, browser); - // assign to window simulation WebExtension APIs - window.browser = browser; + if (!window?.browser?.extension) { + // assign to window simulation WebExtension APIs + window.browser = browser; + } } const app = new App({ diff --git a/src/ext/shared/dev.js b/src/ext/shared/dev.js index cfde2634..6d9a754c 100644 --- a/src/ext/shared/dev.js +++ b/src/ext/shared/dev.js @@ -470,9 +470,9 @@ const _browser = { new Promise((resolve) => { setTimeout(() => resolve(), _browser.delay); }), - onChanged: { - addListener: () => undefined, - }, + }, + onChanged: { + addListener: () => undefined, }, }, }; diff --git a/src/ext/shared/utils.js b/src/ext/shared/utils.js index c8c1355e..fae3e29e 100644 --- a/src/ext/shared/utils.js +++ b/src/ext/shared/utils.js @@ -186,8 +186,8 @@ export const validMetaKeys = new Set([ ]); export const extensionPaths = { - popup: "/dist/s/entry-ext-action-popup.html", - page: "/dist/s/entry-ext-extension-page.html", + popup: "/dist/entry-ext-action-popup.html", + page: "/dist/entry-ext-extension-page.html", }; export async function openExtensionPage() { diff --git a/vite.config.js b/vite.config.js index 81d75297..f7cf2b45 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,34 +1,25 @@ import { defineConfig } from "vite"; import { svelte } from "@sveltejs/vite-plugin-svelte"; -// [inline-svg] -// TODO: remove this once vite resolved issue -// https://github.com/vitejs/vite/issues/1204 -// import fs from "fs"; -// import svgpkg from "svg-inline-loader"; -// export function svgInline() { // custom plugin -// return { -// name: "transform-file", -// transform(code, id) { -// if (id.endsWith(".svg")) { -// const svg = fs.readFileSync(id, "utf8"); -// const ret = svgpkg.getExtractedSVG(svg, {}); -// return `export default '${ret}'`; -// } -// } -// }; -// } -// [inline-svg] -// NOW: use `?raw` suffix import svg assets as inline -// https://vitejs.dev/guide/assets.html#importing-asset-as-string +/** + * About `inline-svg` + * use `?raw` suffix import svg assets as inline + * @see {@link https://vitejs.dev/guide/assets.html#importing-asset-as-string} + * Ignore lint errors `{@html}`, since these are deterministic local svg resources, + * there is no risk of Cross-Site Scripting (XSS) attacks and can be safely disabled. + * @see {@link https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-html-tags/} + */ -// [autoprefixer] -// https://vitejs.dev/guide/features.html#postcss -// have config with `.postcssrc.json` file -// about `missing peer postcss` error, ignore it +/** + * About `autoprefixer` + * have config with `.postcssrc.json` file + * @see {@link https://vitejs.dev/guide/features.html#postcss} + * about `missing peer postcss` error, ignore it + */ -// https://vitejs.dev/config/ +/** @see {@link https://vitejs.dev/config/} */ export default defineConfig({ + publicDir: "public/ext/vendor/", plugins: [svelte()], base: "./", }); diff --git a/xcode/App-Shared/ViewController.swift b/xcode/App-Shared/ViewController.swift index df9befb9..a4dc6e4c 100644 --- a/xcode/App-Shared/ViewController.swift +++ b/xcode/App-Shared/ViewController.swift @@ -24,6 +24,7 @@ class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHan // https://developer.apple.com/documentation/webkit/wkwebview/4111163-inspectable/ self.webView.isInspectable = true } + logger?.debug("\(#function, privacy: .public) - DEBUG mode: isInspectable = true") #endif view = webView self.webView.scrollView.isScrollEnabled = false diff --git a/xcode/Ext-Safari/Resources/_locales/en/messages.json b/xcode/Ext-Safari/Resources/_locales/en/messages.json deleted file mode 100644 index 8db4438d..00000000 --- a/xcode/Ext-Safari/Resources/_locales/en/messages.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extension_name": { - "message": "_NAME_", - "description": "The display name for the extension." - }, - "extension_description": { - "message": "Save and run javascript for the web pages you visit", - "description": "Description of what the extension does." - } -} diff --git a/xcode/Ext-Safari/Resources/ext-v4-manifest.json b/xcode/Ext-Safari/Resources/ext-v4-manifest.json deleted file mode 100644 index dde68d2a..00000000 --- a/xcode/Ext-Safari/Resources/ext-v4-manifest.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "manifest_version": 2, - "default_locale": "en", - "name": "__MSG_extension_name__", - "description": "__MSG_extension_description__", - "version": "_VERSION_", - "icons": { - "48": "images/icon-48.png", - "96": "images/icon-96.png", - "128": "images/icon-128.png", - "256": "images/icon-256.png", - "512": "images/icon-512.png" - }, - "background": { - "scripts": ["dist/background.js"], - "persistent": false - }, - "browser_action": { - "default_popup": "dist/s/entry-ext-action-popup.html", - "default_icon": { - "16": "images/toolbar-icon-16.png", - "32": "images/toolbar-icon-32.png" - } - }, - "content_scripts": [ - { - "js": ["dist/content.js"], - "matches": [""], - "run_at": "document_start", - "all_frames": true - } - ], - "permissions": [ - "", - "clipboardWrite", - "contextMenus", - "declarativeNetRequest", - "declarativeNetRequestWithHostAccess", - "menus", - "nativeMessaging", - "storage", - "tabs", - "unlimitedStorage", - "webNavigation" - ] -} diff --git a/xcode/Ext-Safari/Resources/ext-v5-manifest.json b/xcode/Ext-Safari/Resources/ext-v5-manifest.json deleted file mode 100644 index ead6d695..00000000 --- a/xcode/Ext-Safari/Resources/ext-v5-manifest.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "manifest_version": 2, - "default_locale": "en", - "name": "__MSG_extension_name__", - "description": "__MSG_extension_description__", - "version": "_VERSION_", - "icons": { - "48": "images/icon-48.png", - "96": "images/icon-96.png", - "128": "images/icon-128.png", - "256": "images/icon-256.png", - "512": "images/icon-512.png" - }, - "background": { - "scripts": ["dist/background.js"], - "persistent": false - }, - "browser_action": { - "default_popup": "dist/s/entry-ext-action-popup.html", - "default_icon": { - "16": "images/toolbar-icon-16.png", - "32": "images/toolbar-icon-32.png" - } - }, - "content_scripts": [ - { - "js": ["dist/content.js"], - "matches": [""], - "run_at": "document_start", - "all_frames": true - } - ], - "permissions": [ - "", - "clipboardWrite", - "contextMenus", - "declarativeNetRequestWithHostAccess", - "menus", - "nativeMessaging", - "storage", - "tabs", - "unlimitedStorage", - "webNavigation" - ] -} diff --git a/xcode/Userscripts.xcodeproj/project.pbxproj b/xcode/Userscripts.xcodeproj/project.pbxproj index aca26fad..5b6feb25 100644 --- a/xcode/Userscripts.xcodeproj/project.pbxproj +++ b/xcode/Userscripts.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -106,7 +106,7 @@ 033661A429510B7900CFE179 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/View.storyboard; sourceTree = ""; }; 039F59522AD9591C002E9977 /* dist */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dist; sourceTree = ""; }; 039F59552ADA2FE2002E9977 /* USchemeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = USchemeHandler.swift; sourceTree = ""; }; - 039F595A2ADFB312002E9977 /* ext-v5-manifest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "ext-v5-manifest.json"; sourceTree = ""; }; + 039F59662B03AE5A002E9977 /* Userscripts-Vite.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Userscripts-Vite.xcconfig"; sourceTree = ""; }; 03C24F962ABD2CBB00F130F9 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; 03E20D05291E170000B4F692 /* dist */ = {isa = PBXFileReference; lastKnownFileType = folder; path = dist; sourceTree = ""; }; 4A143AA9279DE6FF0029BFD0 /* Mac-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Mac-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -134,7 +134,7 @@ 4A57BA07227235CE008A9763 /* SafariWebExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariWebExtensionHandler.swift; sourceTree = ""; }; 4A57BA0E227235CE008A9763 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4A57BA1D227235E6008A9763 /* Mac.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Mac.entitlements; sourceTree = ""; }; - 4AD66D2026826D8100B004E8 /* ext-v4-manifest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "ext-v4-manifest.json"; sourceTree = ""; }; + 4AD66D2026826D8100B004E8 /* manifest.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = manifest.json; sourceTree = ""; }; 4AED6491268CDB58001794BF /* Functions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Functions.swift; sourceTree = ""; }; 78391D4629A4CB3C00979E34 /* Userscripts-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Userscripts-Debug.xcconfig"; sourceTree = ""; }; 78391D4729A4CB3C00979E34 /* Userscripts-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Userscripts-Release.xcconfig"; sourceTree = ""; }; @@ -288,8 +288,7 @@ 4A36A617268266B30018536B /* _locales */, 4A36A616268266B30018536B /* images */, 03E20D05291E170000B4F692 /* dist */, - 4AD66D2026826D8100B004E8 /* ext-v4-manifest.json */, - 039F595A2ADFB312002E9977 /* ext-v5-manifest.json */, + 4AD66D2026826D8100B004E8 /* manifest.json */, ); path = Resources; sourceTree = ""; @@ -297,6 +296,7 @@ 7878ED2E299BBEBF00E36A24 /* xcconfig */ = { isa = PBXGroup; children = ( + 039F59662B03AE5A002E9977 /* Userscripts-Vite.xcconfig */, 78391D4629A4CB3C00979E34 /* Userscripts-Debug.xcconfig */, 78391D4729A4CB3C00979E34 /* Userscripts-Release.xcconfig */, 7878ED38299BBEBF00E36A24 /* Mac-App.xcconfig */, @@ -419,6 +419,7 @@ 4A57B9E4227235CD008A9763 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1320; LastUpgradeCheck = 1420; ORGANIZATIONNAME = "Justin Wasack"; @@ -705,6 +706,48 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 039F59602B03A48A002E9977 /* Vite */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 039F59662B03AE5A002E9977 /* Userscripts-Vite.xcconfig */; + buildSettings = { + }; + name = Vite; + }; + 039F59612B03A48A002E9977 /* Vite */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7878ED38299BBEBF00E36A24 /* Mac-App.xcconfig */; + buildSettings = { + }; + name = Vite; + }; + 039F59622B03A48A002E9977 /* Vite */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7878ED32299BBEBF00E36A24 /* Mac-Safari-Extension.xcconfig */; + buildSettings = { + }; + name = Vite; + }; + 039F59632B03A48A002E9977 /* Vite */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7878ED34299BBEBF00E36A24 /* iOS-App.xcconfig */; + buildSettings = { + }; + name = Vite; + }; + 039F59642B03A48A002E9977 /* Vite */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7878ED2F299BBEBF00E36A24 /* iOS-Safari-Extension.xcconfig */; + buildSettings = { + }; + name = Vite; + }; + 039F59652B03A48A002E9977 /* Vite */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7878ED31299BBEBF00E36A24 /* Mac-Tests.xcconfig */; + buildSettings = { + }; + name = Vite; + }; 4A143AAF279DE6FF0029BFD0 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7878ED31299BBEBF00E36A24 /* Mac-Tests.xcconfig */; @@ -795,56 +838,62 @@ 4A143AB1279DE6FF0029BFD0 /* Build configuration list for PBXNativeTarget "Mac-Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( + 039F59652B03A48A002E9977 /* Vite */, 4A143AAF279DE6FF0029BFD0 /* Debug */, 4A143AB0279DE6FF0029BFD0 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 4A4CF716270A38BF00111584 /* Build configuration list for PBXNativeTarget "iOS-Safari-Extension" */ = { isa = XCConfigurationList; buildConfigurations = ( + 039F59642B03A48A002E9977 /* Vite */, 4A4CF714270A38BF00111584 /* Debug */, 4A4CF715270A38BF00111584 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 4A4CF717270A38BF00111584 /* Build configuration list for PBXNativeTarget "iOS-App" */ = { isa = XCConfigurationList; buildConfigurations = ( + 039F59632B03A48A002E9977 /* Vite */, 4A4CF711270A38BF00111584 /* Debug */, 4A4CF712270A38BF00111584 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 4A57B9E7227235CD008A9763 /* Build configuration list for PBXProject "Userscripts" */ = { isa = XCConfigurationList; buildConfigurations = ( + 039F59602B03A48A002E9977 /* Vite */, 4A57BA14227235CE008A9763 /* Debug */, 4A57BA15227235CE008A9763 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 4A57BA16227235CE008A9763 /* Build configuration list for PBXNativeTarget "Mac-Safari-Extension" */ = { isa = XCConfigurationList; buildConfigurations = ( + 039F59622B03A48A002E9977 /* Vite */, 4A57BA17227235CE008A9763 /* Debug */, 4A57BA18227235CE008A9763 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; 4A57BA1A227235CE008A9763 /* Build configuration list for PBXNativeTarget "Mac-App" */ = { isa = XCConfigurationList; buildConfigurations = ( + 039F59612B03A48A002E9977 /* Vite */, 4A57BA1B227235CE008A9763 /* Debug */, 4A57BA1C227235CE008A9763 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; + defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; diff --git a/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Userscripts Extension.xcscheme b/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Mac-Vite-Dev.xcscheme similarity index 53% rename from xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Userscripts Extension.xcscheme rename to xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Mac-Vite-Dev.xcscheme index bf2b16e1..0a3c056b 100644 --- a/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Userscripts Extension.xcscheme +++ b/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Mac-Vite-Dev.xcscheme @@ -1,26 +1,11 @@ + LastUpgradeVersion = "1500" + version = "1.7"> - - - - @@ -38,19 +23,11 @@ - - - - + shouldUseLaunchSchemeArgsEnv = "YES" + shouldAutocreateTestPlan = "YES"> @@ -65,63 +42,48 @@ - - - + allowLocationSimulation = "YES"> + - - - - - + + debugDocumentVersioning = "YES"> + buildConfiguration = "Vite"> diff --git a/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Userscripts.xcscheme b/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Mac.xcscheme similarity index 83% rename from xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Userscripts.xcscheme rename to xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Mac.xcscheme index e3d1c38e..d78f492e 100644 --- a/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Userscripts.xcscheme +++ b/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/Mac.xcscheme @@ -1,7 +1,7 @@ + LastUpgradeVersion = "1500" + version = "1.7"> @@ -15,7 +15,7 @@ @@ -26,16 +26,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + shouldUseLaunchSchemeArgsEnv = "YES" + shouldAutocreateTestPlan = "YES"> @@ -64,7 +56,7 @@ @@ -81,7 +73,7 @@ diff --git a/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/iOS-Vite-Dev.xcscheme b/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/iOS-Vite-Dev.xcscheme new file mode 100644 index 00000000..c87e739c --- /dev/null +++ b/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/iOS-Vite-Dev.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme b/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme new file mode 100644 index 00000000..9c0ceed5 --- /dev/null +++ b/xcode/Userscripts.xcodeproj/xcshareddata/xcschemes/iOS.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xcode/xcconfig/Mac-App.xcconfig b/xcode/xcconfig/Mac-App.xcconfig index d477275f..7734d6a3 100644 --- a/xcode/xcconfig/Mac-App.xcconfig +++ b/xcode/xcconfig/Mac-App.xcconfig @@ -9,11 +9,13 @@ GENERATE_INFOPLIST_FILE = YES INFOPLIST_FILE = $(SRC_DIR)/Info.plist INFOPLIST_KEY_CFBundleDisplayName = $(PROJECT_NAME)-$(TARGET_NAME) INFOPLIST_KEY_CFBundleDisplayName[config=Debug] = $(PROJECT_NAME)-$(TARGET_NAME)-Debug +INFOPLIST_KEY_CFBundleDisplayName[config=Vite] = $(PROJECT_NAME)-$(TARGET_NAME)-Vite LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks MARKETING_VERSION = $(MAC_APP_VERSION) PRODUCT_BUNDLE_IDENTIFIER = $(APP_IDENTIFIER) PRODUCT_NAME = $(PROJECT_NAME) PRODUCT_NAME[config=Debug] = $(PROJECT_NAME)-Debug +PRODUCT_NAME[config=Vite] = $(PROJECT_NAME)-Vite // Override this file #include? "Mac-App.dev.xcconfig" diff --git a/xcode/xcconfig/Mac-Safari-Extension.xcconfig b/xcode/xcconfig/Mac-Safari-Extension.xcconfig index 6e392d8a..74251cf9 100644 --- a/xcode/xcconfig/Mac-Safari-Extension.xcconfig +++ b/xcode/xcconfig/Mac-Safari-Extension.xcconfig @@ -1,4 +1,6 @@ -SRC_DIR = Ext-Safari +// Shared config file +#include? "Safari-Extension.xcconfig" + CODE_SIGN_ENTITLEMENTS = $(SRC_DIR)/Mac.entitlements CURRENT_PROJECT_VERSION = $(MAC_APP_BUILD) ENABLE_HARDENED_RUNTIME = YES @@ -11,9 +13,6 @@ MARKETING_VERSION = $(MAC_APP_VERSION) PRODUCT_BUNDLE_IDENTIFIER = $(EXT_IDENTIFIER) PRODUCT_NAME = $(PROJECT_NAME)-$(TARGET_NAME) SKIP_INSTALL = YES -MANIFEST_FILE = $(SRC_DIR)/Resources/ext-v4-manifest.json -MANIFEST_NAME = $(PROJECT_NAME) -MANIFEST_NAME[config=Debug] = $(PROJECT_NAME)-Debug // Override this file #include? "Mac-Safari-Extension.dev.xcconfig" diff --git a/xcode/xcconfig/Safari-Extension.xcconfig b/xcode/xcconfig/Safari-Extension.xcconfig new file mode 100644 index 00000000..d2724321 --- /dev/null +++ b/xcode/xcconfig/Safari-Extension.xcconfig @@ -0,0 +1,5 @@ +SRC_DIR = Ext-Safari +MANIFEST_FILE = $(SRC_DIR)/Resources/manifest.json +MANIFEST_NAME = $(PROJECT_NAME) +MANIFEST_NAME[config=Debug] = $(PROJECT_NAME)-Debug +MANIFEST_NAME[config=Vite] = $(PROJECT_NAME)-Vite \ No newline at end of file diff --git a/xcode/xcconfig/Userscripts-Base.xcconfig b/xcode/xcconfig/Userscripts-Base.xcconfig index 4113b7fa..6ad773d0 100644 --- a/xcode/xcconfig/Userscripts-Base.xcconfig +++ b/xcode/xcconfig/Userscripts-Base.xcconfig @@ -55,6 +55,7 @@ MTL_FAST_MATH = YES ONLY_ACTIVE_ARCH[config=Debug] = YES SDKROOT = macosx SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug] = DEBUG +SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Vite] = DEBUG SWIFT_COMPILATION_MODE[config=Release] = wholemodule SWIFT_OPTIMIZATION_LEVEL[config=Debug] = -Onone SWIFT_OPTIMIZATION_LEVEL[config=Release] = -O diff --git a/xcode/xcconfig/Userscripts-Release.xcconfig b/xcode/xcconfig/Userscripts-Release.xcconfig index 5bfbafca..94cb3265 100644 --- a/xcode/xcconfig/Userscripts-Release.xcconfig +++ b/xcode/xcconfig/Userscripts-Release.xcconfig @@ -6,6 +6,8 @@ IOS_APP_VERSION = 1.5.0 MAC_APP_BUILD = 83 MAC_APP_VERSION = 4.5.0 +// Development +CODE_SIGN_IDENTITY = Apple Development // Developer Team ID DEVELOPMENT_TEAM = J74Q8V8V8N // Organization Identifier diff --git a/xcode/xcconfig/Userscripts-Vite.xcconfig b/xcode/xcconfig/Userscripts-Vite.xcconfig new file mode 100644 index 00000000..1635bab4 --- /dev/null +++ b/xcode/xcconfig/Userscripts-Vite.xcconfig @@ -0,0 +1,24 @@ +#include "Userscripts-Base.xcconfig" + +INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © Userscripts +IOS_APP_BUILD = 2 +IOS_APP_VERSION = 2.0.0 +MAC_APP_BUILD = 5 +MAC_APP_VERSION = 5.0.0 + +// Sign to Run Locally +CODE_SIGN_IDENTITY = - +// Organization Identifier +ORG_IDENTIFIER = dev.vite +// Application Identifier +APP_IDENTIFIER = $(ORG_IDENTIFIER).userscripts +// Safari Extension Identifier +EXT_IDENTIFIER = $(APP_IDENTIFIER).ext.safari +// App Groups and Group Containers +IOS_SHARED_GID = group.$(ORG_IDENTIFIER).userscripts +MAC_SHARED_GID = 00000.$(ORG_IDENTIFIER).userscripts +// App URL Scheme +APP_URL_SCHEME = userscripts-vite + +// Override this file +#include? "Userscripts-Vite.dev.xcconfig" diff --git a/xcode/xcconfig/iOS-App.xcconfig b/xcode/xcconfig/iOS-App.xcconfig index 005ffcaf..b1e738bb 100644 --- a/xcode/xcconfig/iOS-App.xcconfig +++ b/xcode/xcconfig/iOS-App.xcconfig @@ -8,6 +8,7 @@ GENERATE_INFOPLIST_FILE = YES INFOPLIST_FILE = $(SRC_DIR)/Info.plist INFOPLIST_KEY_CFBundleDisplayName = $(PROJECT_NAME) INFOPLIST_KEY_CFBundleDisplayName[config=Debug] = $(PROJECT_NAME)-D +INFOPLIST_KEY_CFBundleDisplayName[config=Vite] = $(PROJECT_NAME)-V INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen INFOPLIST_KEY_UIMainStoryboardFile = Main diff --git a/xcode/xcconfig/iOS-Safari-Extension.xcconfig b/xcode/xcconfig/iOS-Safari-Extension.xcconfig index 7df9eae4..f45ffdb6 100644 --- a/xcode/xcconfig/iOS-Safari-Extension.xcconfig +++ b/xcode/xcconfig/iOS-Safari-Extension.xcconfig @@ -1,4 +1,6 @@ -SRC_DIR = Ext-Safari +// Shared config file +#include? "Safari-Extension.xcconfig" + CODE_SIGN_ENTITLEMENTS = $(SRC_DIR)/iOS.entitlements CURRENT_PROJECT_VERSION = $(IOS_APP_BUILD) GENERATE_INFOPLIST_FILE = YES @@ -15,9 +17,6 @@ SKIP_INSTALL = YES SWIFT_EMIT_LOC_STRINGS = YES TARGETED_DEVICE_FAMILY = 1,2 VALIDATE_PRODUCT[config=Release] = YES -MANIFEST_FILE = $(SRC_DIR)/Resources/ext-v4-manifest.json -MANIFEST_NAME = $(PROJECT_NAME) -MANIFEST_NAME[config=Debug] = $(PROJECT_NAME)-Debug // Override this file #include? "iOS-Safari-Extension.dev.xcconfig"