Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to manifest V3 for Chrome, update tech stack, major refactoring #40

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 4
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,35 @@ Development

### Build

To compile the plugin into the `build/dest` directory, and pack the ZIP file to `build/web-ext` directory, use the following shell commands:
Install the dependencies:

```console
$ yarn install
$ yarn run build
```

The project supports several build options. Use the following commands based on your needs:

- **Development with hot reload**:
Launches a development server with hot reload. The extension files are placed in the `build/dest` directory.
```console
$ yarn run dev # for Chromium-based browsers (manifest v3)
$ yarn run dev:firefox # for Firefox-based browsers (manifest v2)
```

- **Build for production**:
Creates a ZIP file of the extension in the `build/web-ext` directory.
```console
$ yarn run build # for Chromium-based browsers (manifest v3)
$ yarn run build:firefox # for Firefox-based browsers (manifest v2)
```

- **Publish for multiple browsers**:
Builds the extension for both Chrome and Firefox, generating two ZIP files in the `build/web-ext` directory.
```console
$ yarn run publish
```


### Test

```console
Expand Down
78 changes: 38 additions & 40 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,42 +1,40 @@
{
"name": "msdn-delocalizer",
"version": "1.1.0",
"description": "Browser extension to force de-localization of Microsoft documentation pages",
"main": "index.js",
"scripts": {
"manifest": "copyfiles --flat src/manifest.json LICENSE.md build/dest",
"license": "copyfiles --flat LICENSE.md build/dest",
"icon": "magick convert src/icon.svg build/dest/icon.png",
"resources": "npm run manifest && npm run license",
"typescript": "tsc",
"browserify": "browserify build/src/background.js --outfile build/dest/background.js",
"package": "web-ext build -s build/dest -a build/web-ext",
"build": "npm run resources && npm run typescript && npm run browserify && npm run package",
"test": "mocha build/test"
},
"repository": {
"type": "git",
"url": "https://github.com/ForNeVeR/msdn-delocalizer"
},
"keywords": [
"msdn",
"microsoft",
"docs"
],
"author": "Friedrich von Never",
"license": "MIT",
"bugs": {
"url": "https://github.com/ForNeVeR/msdn-delocalizer/issues"
},
"homepage": "https://github.com/ForNeVeR/msdn-delocalizer",
"devDependencies": {
"@types/assert": "^1.5.5",
"@types/chrome": "0.0.91",
"@types/mocha": "^7.0.2",
"browserify": "^10.2.6",
"copyfiles": "^2.2.0",
"mocha": "^2.2.4",
"typescript": "^3.8.3",
"web-ext": "^6.3.0"
}
"name": "msdn-delocalizer",
"version": "1.1.0",
"description": "Browser extension to force de-localization of Microsoft documentation pages",
"type": "module",
"scripts": {
"icon": "magick convert src/icon.svg src/assets/icon.png",
"test": "vitest run",
"build": "vite build",
"build:firefox": "cross-env TARGET=firefox vite build",
"dev": "vite dev",
"dev:firefox": "cross-env TARGET=firefox vite dev",
"publish": "cross-env PUBLISH=1 yarn build && cross-env PUBLISH=1 yarn build:firefox"
},
"repository": {
"type": "git",
"url": "https://github.com/ForNeVeR/msdn-delocalizer"
},
"keywords": [
"msdn",
"microsoft",
"docs"
],
"author": "Friedrich von Never",
"license": "MIT",
"bugs": {
"url": "https://github.com/ForNeVeR/msdn-delocalizer/issues"
},
"homepage": "https://github.com/ForNeVeR/msdn-delocalizer",
"devDependencies": {
"@types/chrome": "0.0.280",
"cross-env": "^7.0.3",
"typescript": "^5.6.3",
"vite": "^5.4.10",
"vite-plugin-web-extension": "^4.3.1",
"vitest": "^2.1.4",
"web-ext": "^8.3.0",
"zip-a-folder": "^3.1.8"
}
}
File renamed without changes
13 changes: 0 additions & 13 deletions src/background.ts

This file was deleted.

44 changes: 44 additions & 0 deletions src/build-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { normalizePath } from "vite";
import * as path from "path";
import * as fs from "fs";
import { zip } from "zip-a-folder";

// normalize path for windows compatibility
export const resolvePath = (...args: string[]) =>
normalizePath(path.resolve(...args));

// normalize path for windows compatibility
export const joinPath = (...args: string[]) =>
normalizePath(path.join(...args));

export const destFolder = resolvePath("build", "dest");
const webExtFolder = resolvePath("build", "web-ext");

export const copyLicenceFileToDestFolder = async () => {
const destFolder = resolvePath("build", "dest");

await fs.promises.copyFile(
resolvePath("LICENSE.md"),
joinPath(destFolder, "LICENSE.md")
);
};

export const createWebExtensionZipFile = async (targetBrowserName: string) => {
fs.access(webExtFolder, async (error) => {
if (!error) return;

await fs.promises.mkdir(webExtFolder);
});

const webExtFilename = `msdn-delocalizer-${targetBrowserName}.zip`;
const webExtPath = joinPath(webExtFolder, webExtFilename);

await zip(destFolder, webExtPath);
};

export const cleanupDestFolder = async () => {
await fs.promises.rm(destFolder, {
recursive: true,
force: true,
});
}
45 changes: 27 additions & 18 deletions src/manifest.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
{
"manifest_version": 2,
"name": "msdn-delocalizer",
"description": "Browser extension to force de-localization of Microsoft documentation pages",
"version": "1.1.0",
"permissions": [
"https://docs.microsoft.com/*",
"https://msdn.microsoft.com/*",
"https://learn.microsoft.com/*",
"tabs"
],
"background": {
"scripts": [
"background.js"
"{{chrome}}.manifest_version": 3,
"{{firefox}}.manifest_version": 2,
"name": "msdn-delocalizer",
"description": "Browser extension to force de-localization of Microsoft documentation pages",
"version": "1.1.0",
"{{chrome}}.permissions": ["tabs"],
"{{chrome}}.host_permissions": [
"https://docs.microsoft.com/*",
"https://msdn.microsoft.com/*",
"https://learn.microsoft.com/*"
],
"persistent": false
},
"icons": {
"128": "icon.png"
}
"{{firefox}}.permissions": [
"https://docs.microsoft.com/*",
"https://msdn.microsoft.com/*",
"https://learn.microsoft.com/*",
"tabs"
],
"{{chrome}}.background": {
"service_worker": "service-worker.ts",
"type": "module"
},
"{{firefox}}.background": {
"scripts": ["service-worker.ts"],
"persistent": false
},
"icons": {
"128": "icon.png"
}
}
14 changes: 14 additions & 0 deletions src/service-worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { delocalizeUrl } from "./url-utils";

chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
if (changeInfo.url == null) return;

const tabUrl = new URL(changeInfo.url);
const replacementUrl = delocalizeUrl(tabUrl);
if (!replacementUrl || replacementUrl.toString() == tabUrl.toString())
return;

chrome.tabs.update(tabId, {
url: replacementUrl.toString(),
});
});
32 changes: 22 additions & 10 deletions src/url-utils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
var microsoftDocumentationSites = ['docs.microsoft.com', 'msdn.microsoft.com', 'learn.microsoft.com'];
const microsoftDocumentationSites = [
"docs.microsoft.com",
"msdn.microsoft.com",
"learn.microsoft.com",
];

export function isMicrosoftDocumentationUrl(url: URL): boolean {
return microsoftDocumentationSites.includes(url.host);
return microsoftDocumentationSites.includes(url.host);
}

var pathNameLanguageRegex = /^\/([a-zA-Z]{2}-[a-zA-Z]{2})\//;
var englishPathName = '/en-us/';
const pathNameLanguageRegex = /^\/([a-zA-Z]{2}-[a-zA-Z]{2})\//;
const englishPathName = "/en-us/";

export function delocalizeUrl(url: URL): URL | null {
if (!isMicrosoftDocumentationUrl(url)) return null;
var pathName = url.pathname;
var newPathName = pathName.replace(pathNameLanguageRegex, englishPathName);
var result = new URL(url.toString());
result.pathname = newPathName;
return result;
if (!isMicrosoftDocumentationUrl(url)) return null;

const pathName = url.pathname;
const newPathName = pathName.replace(
pathNameLanguageRegex,
englishPathName
);

const result = new URL(url.toString());
result.pathname = newPathName;

return result;
}
36 changes: 0 additions & 36 deletions test/url-utils-test.ts

This file was deleted.

53 changes: 53 additions & 0 deletions test/url-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { describe, it, expect } from "vitest";
import { delocalizeUrl, isMicrosoftDocumentationUrl } from "../src/url-utils";

describe("UrlUtils", () => {
describe("isMicrosoftDocumentationUrl", () => {
it("should return true for msdn.microsoft.com, docs.microsoft.com, and learn.microsoft.com", () => {
expect(
isMicrosoftDocumentationUrl(
new URL("https://learn.microsoft.com/abcd")
)
).toBe(true);
expect(
isMicrosoftDocumentationUrl(
new URL("https://docs.microsoft.com/abcd")
)
).toBe(true);
expect(
isMicrosoftDocumentationUrl(
new URL("https://msdn.microsoft.com/abcd")
)
).toBe(true);
});

it("should return false for other sites", () => {
expect(
isMicrosoftDocumentationUrl(
new URL("https://example.microsoft.com/")
)
).toBe(false);
});
});

describe("delocalizeUrl", () => {
it("should return null for non-Microsoft documentation URL", () => {
expect(delocalizeUrl(new URL("http://example.com"))).toBeNull();
});

it("should return the same URL for non-localized input", () => {
var input = new URL("http://msdn.microsoft.com/no-localization");
expect(delocalizeUrl(input)?.toString(), input.toString());
});

it("should return the English URL for localized input", () => {
var input = new URL(
"https://msdn.microsoft.com/ru-ru/library/t0zfk0w1.aspx"
);
expect(
delocalizeUrl(input)?.toString(),
"https://msdn.microsoft.com/en-us/library/t0zfk0w1.aspx"
);
});
});
});
14 changes: 7 additions & 7 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"lib": ["dom", "ES2016"],
"outDir": "build",
"strict": true
}
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"lib": ["dom", "esnext"],
"outDir": "build",
"strict": true
}
}
Loading