Skip to content

Commit

Permalink
🏗️ [Socialite] Author new package (#1)
Browse files Browse the repository at this point in the history
* 🏗️ [Socialite] Author new package

* ✨ [Socialite] Now mostly working

* 👷 [Socialite] Majority test coverage

* 🔥 [Network] Remove title property

* ✨ [Socialite] Now supporting both string and RegExp types

* 🏗️ [Socialite] Add all unique social networks

* 👷 [Socialite] Test coverage for each social network

* ♻️ [Socialite] No longer capture subdomain from regex

* ♻️ [Socialite] No longer allow a single slash in path

* ✨ [Socialite] Now supporting subdomain users

* 🚚 [Tests] Split social network tests into separate files

* 🎨 [Helpers] Improve readability of getUrlGroups

* 🚚 [Utilities] Better organization

* 💩 [Utilities] Removing regex util because of mysterious circular dep

* 🎨 [Socialite] A bit of method re-org

* ⬆️ [Dependency] Bump all deps

* 🔧 [Eslint] Enable partially accurate jest linting for vitest

* 🎨 [Tests] Lint all test files

* ⬆️ [Dependency] Define c8 as dependency

* 👷 [Utilities] Author tests

* 👍 [Socialite] Review cleanup
  • Loading branch information
beefchimi committed Jan 16, 2022
1 parent f2da298 commit 25db0ed
Show file tree
Hide file tree
Showing 82 changed files with 3,410 additions and 512 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"extends": [
"plugin:@beefchimi/esnext",
"plugin:@beefchimi/typescript",
"plugin:@beefchimi/jest",
"plugin:@beefchimi/prettier"
]
}
1,425 changes: 930 additions & 495 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,20 @@
"scripts": {
"lint": "eslint 'src/**/*.{ts,tsx}'",
"test": "vitest",
"coverage": "vitest --coverage",
"coverage": "vitest --coverage --run",
"build": "npm run clean && tsc && vite build",
"clean": "rm -rf dist",
"clean": "rm -rf coverage && rm -rf dist",
"nuke": "npm run clean && rm -rf node_modules && rm -rf package-lock.json && npm cache clean --force"
},
"devDependencies": {
"@beefchimi/browserslist-config": "^0.0.7",
"@beefchimi/eslint-plugin": "^0.0.7",
"@beefchimi/prettier-config": "^0.0.7",
"@beefchimi/typescript-config": "^0.0.7",
"@beefchimi/browserslist-config": "^0.0.8",
"@beefchimi/eslint-plugin": "^0.0.8",
"@beefchimi/prettier-config": "^0.0.8",
"@beefchimi/typescript-config": "^0.0.8",
"@types/node": "^17.0.8",
"vite": "^2.7.10",
"vitest": "^0.0.139",
"vite-plugin-dts": "^0.9.8"
"c8": "^7.11.0",
"vite": "^2.7.12",
"vite-plugin-dts": "^0.9.9",
"vitest": "^0.1.17"
}
}
39 changes: 39 additions & 0 deletions src/capture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {UrlCaptureId} from './types';

// NOTE: Don't be mislead by the `\\` in some capture groups.
// This is a consequence of embedding within a `string`.
// Once constructed by `RegExp()`, it will be properly reduced to a single `\`.

function constructFullLineRegExp(...captureGroups: (string | RegExp)[]) {
return new RegExp(['^', ...captureGroups, '$'].join(''));
}

export const urlCaptureGroup = {
scheme: `(?<${UrlCaptureId.Scheme}>https?://)?`,
domain: `(?<${UrlCaptureId.Domain}>[\\w\\.-]+?)`,
tldomain: `(?<${UrlCaptureId.Tldomain}>\\.\\w{2,5}[/]?)?`,
port: `(?<${UrlCaptureId.Port}>:\\d+?[/]?)?`,
path: `(?<${UrlCaptureId.Path}>\\/.+?(?=[\\?|#]?))?`,
parameters: `(?<${UrlCaptureId.Parameters}>\\?.+?(?=[#]?))?`,
anchor: `(?<${UrlCaptureId.Anchor}>\\#.+?)?`,
};

export const urlRegExp = constructFullLineRegExp(
urlCaptureGroup.scheme,
urlCaptureGroup.domain,
urlCaptureGroup.tldomain,
urlCaptureGroup.port,
urlCaptureGroup.path,
urlCaptureGroup.parameters,
urlCaptureGroup.anchor,
);

export const profileReplacement = {
user: '{REPLACE_PROFILE_USER}',
prefix: '{REPLACE_PROFILE_PREFIX}',
};

export const defaultUserMatcher = {
subdomain: /[^.]+/,
path: /[^/]+/,
};
13 changes: 13 additions & 0 deletions src/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as networks from './networks';

export const allSocialNetworks = Object.values(networks);
export const defaultSocialNetworks = [
networks.facebook,
networks.instagram,
networks.linkedin,
networks.reddit,
networks.tiktok,
networks.twitch,
networks.twitter,
networks.youtube,
];
30 changes: 26 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
import type {SocialiteTest} from './types';
export {
urlCaptureGroup,
urlRegExp,
profileReplacement,
defaultUserMatcher,
} from './capture';

export function socialite({message = '@beefchimi'}: SocialiteTest) {
return `This is a ${message} package!`;
}
export {allSocialNetworks, defaultSocialNetworks} from './data';
export {socialNetworkPrefixes} from './prefixes';
export {Socialite} from './socialite';

export {
filterNullishValuesFromObject,
filterNetworkProperties,
mergeRegExp,
getUrlGroups,
getUrlWithSubstitutions,
} from './utilities';

export {MatchUserSource, UrlCaptureId} from './types';
export type {
UrlAnatomy,
SocialProfile,
SocialNetwork,
SocialNetworkProperty,
SocialNetworkProperties,
} from './types';
10 changes: 10 additions & 0 deletions src/networks/behance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const behance: SocialNetwork = {
id: 'behance',
preferredUrl: `https://behance.net/${profileReplacement.user}`,
matcher: {
domain: /behance/,
},
};
10 changes: 10 additions & 0 deletions src/networks/devto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const devto: SocialNetwork = {
id: 'dev_to',
preferredUrl: `https://dev.to/${profileReplacement.user}`,
matcher: {
domain: /^dev$/,
},
};
11 changes: 11 additions & 0 deletions src/networks/discord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const discord: SocialNetwork = {
id: 'discord',
preferredUrl: `https://discordapp.com/users/${profileReplacement.user}`,
matcher: {
domain: /discord/,
user: /^(?:\/users\/)?(?:\/)?([^/]+)/,
},
};
10 changes: 10 additions & 0 deletions src/networks/dribbble.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const dribbble: SocialNetwork = {
id: 'dribbble',
preferredUrl: `https://dribbble.com/${profileReplacement.user}`,
matcher: {
domain: /dribbble/,
},
};
11 changes: 11 additions & 0 deletions src/networks/exercism.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const exercism: SocialNetwork = {
id: 'exercism',
preferredUrl: `https://exercism.io/profiles/${profileReplacement.user}`,
matcher: {
domain: /exercism/,
user: /^(?:\/profiles\/)?(?:\/)?([^/]+)/,
},
};
11 changes: 11 additions & 0 deletions src/networks/facebook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const facebook: SocialNetwork = {
id: 'facebook',
preferredUrl: `https://facebook.com/${profileReplacement.user}`,
appUrl: `https://m.facebook.com/${profileReplacement.user}`,
matcher: {
domain: /facebook/,
},
};
10 changes: 10 additions & 0 deletions src/networks/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const github: SocialNetwork = {
id: 'github',
preferredUrl: `https://github.com/${profileReplacement.user}`,
matcher: {
domain: /github/,
},
};
23 changes: 23 additions & 0 deletions src/networks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export {behance} from './behance';
export {devto} from './devto';
export {discord} from './discord';
export {dribbble} from './dribbble';
export {exercism} from './exercism';
export {facebook} from './facebook';
export {github} from './github';
export {instagram} from './instagram';
export {keybase} from './keybase';
export {linkedin} from './linkedin';
export {medium} from './medium';
export {patreon} from './patreon';
export {pinterest} from './pinterest';
export {reddit} from './reddit';
export {stackoverflow} from './stackoverflow';
export {substack} from './substack';
export {telegram} from './telegram';
export {tiktok} from './tiktok';
export {twitch} from './twitch';
export {twitter} from './twitter';
export {vimeo} from './vimeo';
export {yat} from './yat';
export {youtube} from './youtube';
11 changes: 11 additions & 0 deletions src/networks/instagram.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const instagram: SocialNetwork = {
id: 'instagram',
preferredUrl: `https://instagram.com/${profileReplacement.user}`,
appUrl: `https://m.instagram.com/${profileReplacement.user}`,
matcher: {
domain: /instagram/,
},
};
10 changes: 10 additions & 0 deletions src/networks/keybase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const keybase: SocialNetwork = {
id: 'keybase',
preferredUrl: `https://keybase.io/${profileReplacement.user}`,
matcher: {
domain: /keybase/,
},
};
12 changes: 12 additions & 0 deletions src/networks/linkedin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const linkedin: SocialNetwork = {
id: 'linkedin',
preferredUrl: `https://linkedin.com/in/${profileReplacement.user}`,
appUrl: `https://linkedin.com/mwlite/in/${profileReplacement.user}`,
matcher: {
domain: /linkedin/,
user: /^(?:\/mwlite\/)?(?:[/]?in\/)?(?:\/)?([^/]+)/,
},
};
15 changes: 15 additions & 0 deletions src/networks/medium.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {profileReplacement} from '../capture';
import {socialNetworkPrefixes} from '../prefixes';
import type {SocialNetwork} from '../types';

const {medium: prefix} = socialNetworkPrefixes;

export const medium: SocialNetwork = {
id: 'medium',
preferredUrl: `https://medium.com/${prefix}${profileReplacement.user}`,
matcher: {
domain: /medium/,
user: `${prefix}[^\\/]+`,
},
prefix,
};
10 changes: 10 additions & 0 deletions src/networks/patreon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const patreon: SocialNetwork = {
id: 'patreon',
preferredUrl: `https://patreon.com/${profileReplacement.user}`,
matcher: {
domain: /patreon/,
},
};
10 changes: 10 additions & 0 deletions src/networks/pinterest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const pinterest: SocialNetwork = {
id: 'pinterest',
preferredUrl: `https://pinterest.com/${profileReplacement.user}`,
matcher: {
domain: /pinterest/,
},
};
11 changes: 11 additions & 0 deletions src/networks/reddit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const reddit: SocialNetwork = {
id: 'reddit',
preferredUrl: `https://reddit.com/user/${profileReplacement.user}`,
matcher: {
domain: /reddit/,
user: /^(?:\/user\/)?(?:\/)?([^/]+)/,
},
};
11 changes: 11 additions & 0 deletions src/networks/stackoverflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const stackoverflow: SocialNetwork = {
id: 'stackoverflow',
preferredUrl: `https://stackoverflow.com/users/${profileReplacement.user}`,
matcher: {
domain: /stackoverflow/,
user: /^(?:\/users\/)?(?:[/]?\d+)?(?:\/)?([^/]+)/,
},
};
12 changes: 12 additions & 0 deletions src/networks/substack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {profileReplacement} from '../capture';
import {MatchUserSource} from '../types';
import type {SocialNetwork} from '../types';

export const substack: SocialNetwork = {
id: 'substack',
preferredUrl: `https://${profileReplacement.user}.substack.com`,
matcher: {
domain: /substack/,
userSource: MatchUserSource.Subdomain,
},
};
10 changes: 10 additions & 0 deletions src/networks/telegram.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {profileReplacement} from '../capture';
import type {SocialNetwork} from '../types';

export const telegram: SocialNetwork = {
id: 'telegram',
preferredUrl: `https://t.me/${profileReplacement.user}`,
matcher: {
domain: /telegram|t$/,
},
};
29 changes: 29 additions & 0 deletions src/networks/tests/behance.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {allSocialNetworks} from '../../data';
import {Socialite} from '../../socialite';
import type {SocialProfile} from '../../types';
import {mockGenericUser} from '../../tests/fixtures';
import {behance} from '../behance';

describe('Social networks > behance', () => {
const mockSocialite = new Socialite(allSocialNetworks);
const mockCommonUrl = `https://www.behance.net/${mockGenericUser}`;

it('returns expected `id` and `user` from common url', () => {
const {id, user} = mockSocialite.parseProfile(
mockCommonUrl,
) as SocialProfile;

expect(id).toBe(behance.id);
expect(user).toBe(mockGenericUser);
});

it('returns expected `id` and `user` from url with trailing path', () => {
const mockUncommonUrl = `${mockCommonUrl}/trail-123`;
const {id, user} = mockSocialite.parseProfile(
mockUncommonUrl,
) as SocialProfile;

expect(id).toBe(behance.id);
expect(user).toBe(mockGenericUser);
});
});

0 comments on commit 25db0ed

Please sign in to comment.