Skip to content

Commit

Permalink
Add support for Windows (#6)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
connor4312 and sindresorhus authored Mar 7, 2021
1 parent f711a2b commit 818e009
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 19 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ jobs:
- 14
- 12
- 10
- 8
- 6
- 4
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
Expand Down
13 changes: 10 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
'use strict';
const defaultBrowserId = require('default-browser-id');
const bundleName = require('bundle-name');
const windows = require('./windows');

module.exports = () => {
module.exports = async () => {
if (process.platform === 'linux') {
return require('xdg-default-browser')();
}

if (process.platform === 'darwin') {
return defaultBrowserId().then(id => bundleName(id).then(name => ({name, id})));
const id = await defaultBrowserId();
const name = await bundleName(id);
return {name, id};
}

return Promise.reject(new Error('Only macOS and Linux are supported'));
if (process.platform === 'win32') {
return windows();
}

throw new Error('Only macOS, Windows, and Linux are supported');
};
4 changes: 2 additions & 2 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {expectType} from 'tsd';
import defaultBrowser, {Browser} from '.';
import * as defaultBrowser from './index.js';

expectType<Promise<Browser>>(defaultBrowser());
expectType<Promise<defaultBrowser.Browser>>(defaultBrowser());
24 changes: 17 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
"url": "https://sindresorhus.com"
},
"engines": {
"node": ">=4"
"node": ">=12"
},
"scripts": {
"test": "xo && ava && tsd"
},
"files": [
"index.js",
"windows.js",
"index.d.ts"
],
"keywords": [
Expand All @@ -38,14 +39,23 @@
"dependencies": {
"bundle-name": "^2.0.1",
"default-browser-id": "^2.0.0",
"xdg-default-browser": "^2.0.0"
"execa": "^5.0.0",
"xdg-default-browser": "^2.1.0"
},
"devDependencies": {
"ava": "*",
"tsd": "^0.11.0",
"xo": "*"
"ava": "^3.15.0",
"tsd": "^0.14.0",
"xo": "^0.37.1"
},
"xo": {
"esnext": true
"esnext": true,
"overrides": [
{
"files": "test.js",
"rules": {
"node/no-unsupported-features/es-syntax": 0
}
}
]
}
}
56 changes: 52 additions & 4 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
import test from 'ava';
import m from './';
const test = require('ava');
const m = require('.');
const windows = require('./windows');

test(async t => {
t.regex((await m()).id, /^com\./);
test('sane', async t => {
t.regex((await m()).id, /^(com|org)\./);
});

test('windows parsing', async t => {
const cases = [
{
output: '\r\nHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice\r\n ProgId REG_SZ AppXq0fevzme2pys62n3e0fbqa7peapykr8v\r\n\r\n',
expected: 'com.microsoft.edge.old'
},
{
output: '\r\nHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice\r\n ProgId REG_SZ MSEdgeDHTML\r\n\r\n',
expected: 'com.microsoft.edge'
},
{
output: '\r\nHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice\r\n ProgId REG_SZ ChromeHTML\r\n\r\n',
expected: 'com.google.chrome'
},
{
output: '\r\nHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice\r\n ProgId REG_SZ IE.HTTP\r\n\r\n',
expected: 'com.microsoft.ie'
},
{
output: '\r\nHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice\r\n ProgId REG_SZ FirefoxURL\r\n\r\n',
expected: 'org.mozilla.firefox'
},
{
output: '\r\nHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice\r\n ProgId REG_SZ Potato\r\n\r\n',
expected: undefined
},
{
output:
'',
expected: undefined
}
];

await Promise.all(cases.map(async testCase => {
let actual;
try {
actual = await windows(async () => ({stdout: testCase.output}));
} catch (error) {
if (!(error instanceof windows.UnknownBrowserError)) {
throw error;
}
}

t.is(actual && actual.id, testCase.expected);
}));
});
38 changes: 38 additions & 0 deletions windows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';
const execa = require('execa');

// Windows doesn't have browser IDs in the same way macOS/Linux does--give fake
// ones that look real and match the macOS/Linux versions for cross-platform apps.
const windowsBrowserProgIds = {
AppXq0fevzme2pys62n3e0fbqa7peapykr8v: {name: 'Edge', id: 'com.microsoft.edge.old'},
MSEdgeDHTML: {name: 'Edge', id: 'com.microsoft.edge'}, // On macOS, it's "com.microsoft.edgemac"
MSEdgeHTM: {name: 'Edge', id: 'com.microsoft.edge'}, // Newer Edge/Win10 releases
'IE.HTTP': {name: 'Internet Explorer', id: 'com.microsoft.ie'},
FirefoxURL: {name: 'Firefox', id: 'org.mozilla.firefox'},
ChromeHTML: {name: 'Chrome', id: 'com.google.chrome'}
};

class UnknownBrowserError extends Error {}

module.exports = async (_execa = execa) => {
const result = await _execa('reg', [
'QUERY',
' HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice',
'/v',
'ProgId'
]);

const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(result.stdout);
if (!match) {
throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(result.stdout)}`);
}

const browser = windowsBrowserProgIds[match.groups.id];
if (!browser) {
throw new UnknownBrowserError(`Unknown browser ID ${JSON.stringify(browser)}`);
}

return browser;
};

module.exports.UnknownBrowserError = UnknownBrowserError;

0 comments on commit 818e009

Please sign in to comment.