@progfay/github-streaks
Advanced tools
Comparing version 1.0.2 to 2.0.0
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const dayPeriodGenerator_1 = require("./lib/dayPeriodGenerator"); | ||
exports.getLongestStreak = (since, until) => (contributions) => { | ||
const longestStreak = { | ||
from: null, | ||
to: null, | ||
count: 0 | ||
}; | ||
const streak = { | ||
from: null, | ||
to: null, | ||
count: 0 | ||
}; | ||
for (const day of dayPeriodGenerator_1.dayPeriodGenerator(until, since)) { | ||
const key = day.toString(); | ||
if (!contributions.has(key)) | ||
break; | ||
const contribution = contributions.get(key); | ||
if (contribution === 0) { | ||
if (streak.count > longestStreak.count) { | ||
longestStreak.from = streak.from; | ||
longestStreak.to = streak.to; | ||
longestStreak.count = streak.count; | ||
exports.getLongestStreak = void 0; | ||
const Streak_1 = require("./lib/Streak"); | ||
exports.getLongestStreak = contributions => { | ||
let longestStartIndex = -1; | ||
let longestEndIndex = -1; | ||
let startIndex = -1; | ||
let endIndex = -1; | ||
for (let i = 0; i < contributions.length; i++) { | ||
if (contributions[i].count !== 0) { | ||
if (startIndex === -1) | ||
startIndex = i; | ||
endIndex = i; | ||
} | ||
else { | ||
if (startIndex === -1) | ||
continue; | ||
if (longestEndIndex - longestStartIndex <= endIndex - startIndex) { | ||
longestStartIndex = startIndex; | ||
longestEndIndex = endIndex; | ||
} | ||
streak.from = null; | ||
streak.to = null; | ||
streak.count = 0; | ||
continue; | ||
startIndex = -1; | ||
endIndex = -1; | ||
} | ||
streak[streak.to ? 'from' : 'to'] = day; | ||
streak.count++; | ||
} | ||
return streak.count < longestStreak.count ? longestStreak : streak; | ||
if (longestEndIndex - longestStartIndex <= endIndex - startIndex) { | ||
longestStartIndex = startIndex; | ||
longestEndIndex = endIndex; | ||
} | ||
if (longestStartIndex === -1) | ||
return new Streak_1.Streak([]); | ||
return new Streak_1.Streak(contributions.slice(longestStartIndex, longestEndIndex + 1)); | ||
}; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const arg_1 = __importDefault(require("arg")); | ||
const chalk_1 = __importDefault(require("chalk")); | ||
const range_1 = require("./lib/range"); | ||
const GitHubUser_1 = require("./lib/GitHubUser"); | ||
const mergeMap_1 = require("./lib/mergeMap"); | ||
const getLongestStreak_1 = require("./getLongestStreak"); | ||
const getOngoingStreak_1 = require("./getOngoingStreak"); | ||
const Day_1 = require("./lib/Day"); | ||
const showStreak_1 = require("./showStreak"); | ||
const ARG_OPTIONS = { | ||
'--longest': Boolean, | ||
'--since': String, | ||
'--until': String | ||
}; | ||
const getCurrentStreak_1 = require("./getCurrentStreak"); | ||
const convertToTable_1 = require("./lib/convertToTable"); | ||
const calcContributionsStatistics_1 = require("./lib/calcContributionsStatistics"); | ||
const convertStatisticsToRow = (category, statistics) => ({ | ||
Category: category, | ||
' From ~ To ': statistics.days > 0 ? `${statistics.from} ~ ${statistics.to}` : '', | ||
'Day Count': statistics.days.toString() + (statistics.days > 1 ? ' days' : ' day '), | ||
Sum: statistics.sum.toString(), | ||
Max: statistics.max.toString(), | ||
Min: statistics.min.toString(), | ||
Median: statistics.median.toFixed(2), | ||
'Std dev': statistics.stddev.toFixed(2) | ||
}); | ||
const main = async () => { | ||
const { '--longest': longestFlag = false, '--since': since = '', '--until': until = Day_1.Day.today().toString(), _: [username = ''] } = arg_1.default(ARG_OPTIONS); | ||
const username = process.argv[2]; | ||
const user = new GitHubUser_1.GitHubUser(username); | ||
const { created_at: createdAt } = await user.getUserInfo(); | ||
const joinedDay = new Day_1.Day(createdAt); | ||
const today = Day_1.Day.today(); | ||
const annualDailyContributionsMaps = await Promise.all(range_1.range(joinedDay.getFullYear(), today.getFullYear() + 1) | ||
.map(year => user.getDailyContributions(year))); | ||
const allDailyContributions = mergeMap_1.mergeMap(...annualDailyContributionsMaps); | ||
showStreak_1.showStreak(allDailyContributions, longestFlag | ||
? getLongestStreak_1.getLongestStreak(new Day_1.Day(since || createdAt), new Day_1.Day(until)) | ||
: getOngoingStreak_1.getOngoingStreak); | ||
const joinedYear = parseInt(createdAt.substring(0, 4), 10); | ||
const thisYear = new Date().getFullYear(); | ||
const annualDailyContributionsMaps = await Promise.all(range_1.range(joinedYear, thisYear + 1) | ||
.map(year => user.getAnnualDailyContributions(year))); | ||
const allDailyContributions = annualDailyContributionsMaps.flat(); | ||
const currentStreak = getCurrentStreak_1.getCurrentStreak(allDailyContributions); | ||
const longestStreak = getLongestStreak_1.getLongestStreak(allDailyContributions); | ||
const rows = [ | ||
convertStatisticsToRow('All Contributions', calcContributionsStatistics_1.calcContributionsStatistics(allDailyContributions)), | ||
convertStatisticsToRow('Current Streak', currentStreak.statistics), | ||
convertStatisticsToRow('Longest Streak', longestStreak.statistics) | ||
]; | ||
const table = convertToTable_1.convertToTable(rows, ['Category', ' From ~ To ', 'Day Count', 'Sum', 'Max', 'Min', 'Median', 'Std dev']); | ||
console.log(table); | ||
}; | ||
main() | ||
.catch(({ message }) => { | ||
console.error(chalk_1.default.red(message)); | ||
console.error(message); | ||
}); |
@@ -6,4 +6,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const node_fetch_1 = __importDefault(require("node-fetch")); | ||
const fetchElements_1 = require("./fetchElements"); | ||
exports.GitHubUser = void 0; | ||
const https_1 = __importDefault(require("https")); | ||
const fast_html_parser_1 = __importDefault(require("fast-html-parser")); | ||
const GITHUB_USERNAME_REGEXP = /^@?[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; | ||
@@ -21,24 +22,61 @@ class GitHubUser { | ||
async getUserInfo() { | ||
const response = await node_fetch_1.default(`https://api.github.com/users/${this.username}`); | ||
const information = await response.json(); | ||
if (!information.id) | ||
throw Error(information.message || JSON.stringify(information)); | ||
return information; | ||
const text = await new Promise((resolve, reject) => { | ||
let text = ''; | ||
https_1.default.get({ | ||
protocol: 'https:', | ||
hostname: 'api.github.com', | ||
path: `/users/${this.username}`, | ||
headers: { 'User-Agent': '@progfay/github-streaks' } | ||
}, res => { | ||
res.setEncoding('utf-8'); | ||
res.on('data', (chunk) => { text += chunk.toString(); }); | ||
res.on('end', () => resolve(text)); | ||
res.on('error', reject); | ||
}); | ||
}); | ||
try { | ||
const information = JSON.parse(text); | ||
if (!information.id) | ||
throw Error(); | ||
return information; | ||
} | ||
catch { | ||
throw new Error(text); | ||
} | ||
} | ||
async getDailyContributions(year) { | ||
async getAnnualDailyContributions(year) { | ||
if (year <= 0 || !Number.isInteger(year)) { | ||
throw Error('Second argument must be positive integer.'); | ||
} | ||
const url = `https://github.com/users/${this.username}/contributions?from=${year}-12-01&to=${year}-12-31`; | ||
const elements = await fetchElements_1.fetchElements(url, 'rect.day'); | ||
const html = await new Promise((resolve, reject) => { | ||
let text = ''; | ||
https_1.default.get(`https://github.com/users/${this.username}/contributions?from=${year}-12-01&to=${year}-12-31`, res => { | ||
res.setEncoding('utf-8'); | ||
res.on('data', (chunk) => { text += chunk.toString(); }); | ||
res.on('end', () => resolve(text)); | ||
res.on('error', reject); | ||
}); | ||
}); | ||
const root = fast_html_parser_1.default.parse(html, { | ||
lowerCaseTagName: false, | ||
script: false, | ||
style: false, | ||
pre: false | ||
}); | ||
const elements = root.querySelectorAll('rect.day'); | ||
if (elements.length === 0) | ||
throw new Error('No contributions found.'); | ||
const map = new Map(); | ||
const contributions = []; | ||
for (const { attributes } of elements) { | ||
const { 'data-date': date, 'data-count': count } = attributes; | ||
map.set(date, parseInt(count, 10)); | ||
if (!date.startsWith(`${year}-`)) | ||
continue; | ||
contributions.push({ | ||
day: date, | ||
count: parseInt(count, 10) | ||
}); | ||
} | ||
return map; | ||
return contributions; | ||
} | ||
} | ||
exports.GitHubUser = GitHubUser; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.range = void 0; | ||
exports.range = (start, end) => { | ||
@@ -4,0 +5,0 @@ if (!Number.isInteger(start) || !Number.isInteger(end)) { |
{ | ||
"name": "@progfay/github-streaks", | ||
"version": "1.0.2", | ||
"version": "2.0.0", | ||
"description": "Check GitHub streaks from CLI", | ||
@@ -33,24 +33,21 @@ "main": "src/index.ts", | ||
"dependencies": { | ||
"arg": "^4.1.3", | ||
"chalk": "^4.0.0", | ||
"fast-html-parser": "^1.0.1", | ||
"node-fetch": "^2.6.0" | ||
"fast-html-parser": "^1.0.1" | ||
}, | ||
"devDependencies": { | ||
"@types/fast-html-parser": "^1.0.0", | ||
"@types/jest": "^25.2.1", | ||
"@types/jest": "^26.0.14", | ||
"@types/node-fetch": "^2.5.7", | ||
"@typescript-eslint/eslint-plugin": "^2.30.0", | ||
"@typescript-eslint/parser": "^2.30.0", | ||
"eslint": "^6.8.0", | ||
"@typescript-eslint/eslint-plugin": "^4.1.1", | ||
"@typescript-eslint/parser": "^4.1.1", | ||
"eslint": "^7.9.0", | ||
"eslint-config-standard": "^14.1.1", | ||
"eslint-plugin-import": "^2.20.2", | ||
"eslint-plugin-jest": "^23.8.2", | ||
"eslint-plugin-import": "^2.22.0", | ||
"eslint-plugin-jest": "^24.0.1", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-promise": "^4.2.1", | ||
"eslint-plugin-standard": "^4.0.1", | ||
"jest": "^25.5.0", | ||
"jest": "^26.4.2", | ||
"jest-fetch-mock": "^3.0.3", | ||
"ts-jest": "^25.4.0", | ||
"typescript": "^3.8.3" | ||
"ts-jest": "^26.3.0", | ||
"typescript": "^4.0.3" | ||
}, | ||
@@ -57,0 +54,0 @@ "publishConfig": { |
@@ -1,42 +0,53 @@ | ||
import arg from 'arg' | ||
import chalk from 'chalk' | ||
import { range } from './lib/range' | ||
import { GitHubUser } from './lib/GitHubUser' | ||
import { mergeMap } from './lib/mergeMap' | ||
import { getLongestStreak } from './getLongestStreak' | ||
import { getOngoingStreak } from './getOngoingStreak' | ||
import { Day } from './lib/Day' | ||
import { showStreak } from './showStreak' | ||
import { getCurrentStreak } from './getCurrentStreak' | ||
import { convertToTable } from './lib/convertToTable' | ||
import { Statistics } from './type' | ||
import { calcContributionsStatistics } from './lib/calcContributionsStatistics' | ||
const ARG_OPTIONS = { | ||
'--longest': Boolean, | ||
'--since': String, | ||
'--until': String | ||
interface Row { | ||
'Category': string | ||
' From ~ To ': string | ||
'Day Count': string | ||
'Sum': string | ||
'Max': string | ||
'Min': string | ||
'Median': string | ||
'Std dev': string | ||
} | ||
const convertStatisticsToRow = (category: string, statistics: Statistics): Row => ({ | ||
Category: category, | ||
' From ~ To ': statistics.days > 0 ? `${statistics.from} ~ ${statistics.to}` : '', | ||
'Day Count': statistics.days.toString() + (statistics.days > 1 ? ' days' : ' day '), | ||
Sum: statistics.sum.toString(), | ||
Max: statistics.max.toString(), | ||
Min: statistics.min.toString(), | ||
Median: statistics.median.toFixed(2), | ||
'Std dev': statistics.stddev.toFixed(2) | ||
}) | ||
const main = async () => { | ||
const { | ||
'--longest': longestFlag = false, | ||
'--since': since = '', | ||
'--until': until = Day.today().toString(), | ||
_: [username = ''] | ||
} = arg(ARG_OPTIONS) | ||
const username = process.argv[2] | ||
const user = new GitHubUser(username) | ||
const { created_at: createdAt } = await user.getUserInfo() | ||
const joinedDay = new Day(createdAt) | ||
const today = Day.today() | ||
const joinedYear = parseInt(createdAt.substring(0, 4), 10) | ||
const thisYear = new Date().getFullYear() | ||
const annualDailyContributionsMaps = await Promise.all( | ||
range(joinedDay.getFullYear(), today.getFullYear() + 1) | ||
.map(year => user.getDailyContributions(year)) | ||
range(joinedYear, thisYear + 1) | ||
.map(year => user.getAnnualDailyContributions(year)) | ||
) | ||
const allDailyContributions = mergeMap(...annualDailyContributionsMaps) | ||
showStreak( | ||
allDailyContributions, | ||
longestFlag | ||
? getLongestStreak(new Day(since || createdAt), new Day(until)) | ||
: getOngoingStreak | ||
) | ||
const allDailyContributions = annualDailyContributionsMaps.flat() | ||
const currentStreak = getCurrentStreak(allDailyContributions) | ||
const longestStreak = getLongestStreak(allDailyContributions) | ||
const rows = [ | ||
convertStatisticsToRow('All Contributions', calcContributionsStatistics(allDailyContributions)), | ||
convertStatisticsToRow('Current Streak', currentStreak.statistics), | ||
convertStatisticsToRow('Longest Streak', longestStreak.statistics) | ||
] | ||
const table = convertToTable(rows, ['Category', ' From ~ To ', 'Day Count', 'Sum', 'Max', 'Min', 'Median', 'Std dev']) | ||
console.log(table) | ||
} | ||
@@ -46,3 +57,3 @@ | ||
.catch(({ message }) => { | ||
console.error(chalk.red(message)) | ||
console.error(message) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
1
15231
13
331
2
- Removedarg@^4.1.3
- Removedchalk@^4.0.0
- Removednode-fetch@^2.6.0
- Removedansi-styles@4.3.0(transitive)
- Removedarg@4.1.3(transitive)
- Removedchalk@4.1.2(transitive)
- Removedcolor-convert@2.0.1(transitive)
- Removedcolor-name@1.1.4(transitive)
- Removedhas-flag@4.0.0(transitive)
- Removednode-fetch@2.7.0(transitive)
- Removedsupports-color@7.2.0(transitive)
- Removedtr46@0.0.3(transitive)
- Removedwebidl-conversions@3.0.1(transitive)
- Removedwhatwg-url@5.0.0(transitive)