Skip to content
Merged
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
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
"galactus": "^2.0.2",
"graceful-fs": "^4.2.11",
"junk": "^4.0.1",
"parse-author": "^2.0.0",
"plist": "^3.1.0",
"resedit": "^2.0.3",
"semver": "^7.7.2",
Expand All @@ -60,7 +59,6 @@
"@types/debug": "^4.1.12",
"@types/graceful-fs": "^4.1.9",
"@types/node": "~22.10.7",
"@types/parse-author": "^2.0.2",
"@types/plist": "^3.0.5",
"@types/semver": "^7.7.0",
"@types/yargs-parser": "^21.0.3",
Expand Down
38 changes: 37 additions & 1 deletion src/infer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import parseAuthor from 'parse-author';
import path from 'node:path';
import { createRequire } from 'node:module';
import { promisifiedGracefulFs } from './util.js';
Expand All @@ -16,6 +15,43 @@ type PackageJSON = {

const ELECTRON_PACKAGES = ['electron', 'electron-nightly'] as const;

// Inlined from parse-author / author-regex (MIT, Jon Schlinkert)
function authorRegex() {
return /^\s*([^<(]*?)\s*([<(]([^>)]*?)[>)])?\s*([<(]([^>)]*?)[>)])*\s*$/;
}

export function parseAuthor(str: string) {
if (typeof str !== 'string') {
throw new TypeError('expected author to be a string');
}

if (!str || !/\w/.test(str)) {
return {};
}

const match = ([] as (string | undefined)[]).concat.apply([], authorRegex().exec(str) || []);
const author: { name?: string; email?: string; url?: string } = {};

if (match[1]) {
author.name = match[1];
}

for (let i = 2; i < match.length; i++) {
const val = match[i];

if (i % 2 === 0 && val && match[i + 1]) {
if (val.charAt(0) === '<') {
author.email = match[i + 1];
i++;
} else if (val.charAt(0) === '(') {
author.url = match[i + 1];
i++;
}
}
}
return author;
}

async function* walkPackageJSONs(dir: string): AsyncGenerator<{ src: string; pkg: PackageJSON }> {
let prev: string | undefined;
let cur = path.resolve(dir);
Expand Down
42 changes: 41 additions & 1 deletion test/infer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,52 @@ import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import url from 'node:url';
import { getMetadataFromPackageJSON } from '../src/infer.js';
import { getMetadataFromPackageJSON, parseAuthor } from '../src/infer.js';
import { Options } from '../src/types.js';
import semver from 'semver';
import config from './config.json' with { type: 'json' };
import { beforeEach, describe, it, expect } from 'vitest';

describe('parseAuthor', () => {
it('parses name only', () => {
expect(parseAuthor('Foo Bar')).toEqual({ name: 'Foo Bar' });
});

it('parses name and email', () => {
expect(parseAuthor('Foo Bar <foo.bar@example.com>')).toEqual({
name: 'Foo Bar',
email: 'foo.bar@example.com',
});
});

it('parses name, email, and url', () => {
expect(parseAuthor('Foo Bar <foo.bar@example.com> (https://example.com)')).toEqual({
name: 'Foo Bar',
email: 'foo.bar@example.com',
url: 'https://example.com',
});
});

it('parses email and url without a name', () => {
expect(parseAuthor('<foo.bar@example.com> (https://example.com)')).toEqual({
email: 'foo.bar@example.com',
url: 'https://example.com',
});
});

it('returns an empty object for an empty string', () => {
expect(parseAuthor('')).toEqual({});
});

it('returns an empty object for whitespace-only input', () => {
expect(parseAuthor(' ')).toEqual({});
});

it('throws if input is not a string', () => {
expect(() => parseAuthor(123 as unknown as string)).toThrow(TypeError);
});
});

describe('getMetadataFromPackageJSON', () => {
it.each([
['electron-nightly', 'infer-electron-nightly'],
Expand Down
25 changes: 0 additions & 25 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ __metadata:
"@types/debug": "npm:^4.1.12"
"@types/graceful-fs": "npm:^4.1.9"
"@types/node": "npm:~22.10.7"
"@types/parse-author": "npm:^2.0.2"
"@types/plist": "npm:^3.0.5"
"@types/semver": "npm:^7.7.0"
"@types/yargs-parser": "npm:^21.0.3"
Expand All @@ -91,7 +90,6 @@ __metadata:
oxfmt: "npm:^0.44.0"
oxlint: "npm:^1.59.0"
oxlint-tsgolint: "npm:^0.20.0"
parse-author: "npm:^2.0.0"
plist: "npm:^3.1.0"
resedit: "npm:^2.0.3"
semver: "npm:^7.7.2"
Expand Down Expand Up @@ -1185,13 +1183,6 @@ __metadata:
languageName: node
linkType: hard

"@types/parse-author@npm:^2.0.2":
version: 2.0.3
resolution: "@types/parse-author@npm:2.0.3"
checksum: 10c0/a572efe529d410c0550bbf62c3060c06d441edcebf80a50f20d3cd7107bd6ae71bcd7bebb43993e9b1394afab253eedc2f2ae70fbfd8c96df444235513b7ba42
languageName: node
linkType: hard

"@types/plist@npm:^3.0.5":
version: 3.0.5
resolution: "@types/plist@npm:3.0.5"
Expand Down Expand Up @@ -1403,13 +1394,6 @@ __metadata:
languageName: node
linkType: hard

"author-regex@npm:^1.0.0":
version: 1.0.0
resolution: "author-regex@npm:1.0.0"
checksum: 10c0/3f3a5ad6660be010bd5b979fac180f435bd9615e81db2b1cdac081eb3f639461f6c3927ced956e377a5c91cc789e3de3a3e900e296c1423971043c8fd8be0b73
languageName: node
linkType: hard

"balanced-match@npm:^1.0.0":
version: 1.0.2
resolution: "balanced-match@npm:1.0.2"
Expand Down Expand Up @@ -2836,15 +2820,6 @@ __metadata:
languageName: node
linkType: hard

"parse-author@npm:^2.0.0":
version: 2.0.0
resolution: "parse-author@npm:2.0.0"
dependencies:
author-regex: "npm:^1.0.0"
checksum: 10c0/8b4c19523588a4271c89f64e8167be7c80b4765059c865d38a996c37d080c7e5123e3e2d07d47290891628ad27f4dfb692e3b61156c52fcc0af6cdce3ed57afd
languageName: node
linkType: hard

"path-key@npm:^3.1.0":
version: 3.1.1
resolution: "path-key@npm:3.1.1"
Expand Down
Loading