Socket
Socket
Sign inDemoInstall

devstats

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

devstats - npm Package Compare versions

Comparing version 1.2.1 to 1.3.0

dist/libs/sum-reports.js

44

dist/accounts/codestats.js
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_fetch_1 = require("node-fetch");
const chalk_1 = require("chalk");
const M = require("moment");
const node_fetch_1 = require("node-fetch");
const urls_1 = require("../libs/urls");
const time_1 = require("../time");
const urls_1 = require("../libs/urls");
const BASE_URL = 'https://codestats.net/api/users/';

@@ -28,22 +20,18 @@ class CodeStatsAccount {

}
getReport(day) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.dates.size) {
yield this.fetchDates();
}
return this.dates.has(day) ? this.dates.get(day) : 0;
});
async getReport(day) {
if (!this.dates.size) {
await this.fetchDates();
}
return this.dates.has(day) ? this.dates.get(day) : 0;
}
fetchDates() {
return __awaiter(this, void 0, void 0, function* () {
try {
const userDates = (yield (yield node_fetch_1.default(`${BASE_URL}${this.username}`)).json()).dates;
for (const date in userDates) {
this.dates.set(time_1.getDayIndex(M(date)), userDates[date]);
}
async fetchDates() {
try {
const userDates = (await (await node_fetch_1.default(`${BASE_URL}${this.username}`)).json()).dates;
for (const date in userDates) {
this.dates.set(time_1.getDayIndex(M(date)), userDates[date]);
}
catch (_a) {
return null;
}
});
}
catch (_a) {
return null;
}
}

@@ -50,0 +38,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_fetch_1 = require("node-fetch");
const chalk_1 = require("chalk");
const jsdom_1 = require("jsdom");
const M = require("moment");
const node_fetch_1 = require("node-fetch");
const urls_1 = require("../libs/urls");
const time_1 = require("../time");
const urls_1 = require("../libs/urls");
const BASE_URL = 'https://github.com';

@@ -23,24 +15,22 @@ class GitHubAccount {

}
get canonicalUrl() {
return `https://github.com/${this.username}`;
}
static resolveUrlToId(url) {
return urls_1.parseAccountUrl(url, /\/\/github.com\/([^/\s]+)/i);
}
get canonicalUrl() {
return `https://github.com/${this.username}`;
}
getReport(day) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.contributions.has(day)) {
try {
const html = yield (yield node_fetch_1.default(`${BASE_URL}/${this.username}`)).text();
const document = new jsdom_1.JSDOM(html).window.document;
for (const dayElement of Array.from(document.querySelectorAll('.day'))) {
this.contributions.set(time_1.getDayIndex(M(dayElement.getAttribute('data-date').trim())), parseInt(dayElement.getAttribute('data-count')));
}
async getReport(day) {
if (!this.contributions.has(day)) {
try {
const html = await (await node_fetch_1.default(`${BASE_URL}/${this.username}`)).text();
const document = new jsdom_1.JSDOM(html).window.document;
for (const dayElement of Array.from(document.querySelectorAll('.day'))) {
this.contributions.set(time_1.getDayIndex(M(dayElement.getAttribute('data-date').trim())), parseInt(dayElement.getAttribute('data-count')));
}
catch (_a) {
return null;
}
}
return this.contributions.get(day);
});
catch (_a) {
return null;
}
}
return this.contributions.get(day);
}

@@ -47,0 +37,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_fetch_1 = require("node-fetch");
const chalk_1 = require("chalk");
const M = require("moment");
const node_fetch_1 = require("node-fetch");
const urls_1 = require("../libs/urls");
const time_1 = require("../time");
const urls_1 = require("../libs/urls");
const BASE_URL = 'https://gitlab.com';

@@ -22,27 +14,25 @@ class GitLabAccount {

}
get canonicalUrl() {
return `https://gitlab.com/${this.username}`;
}
static resolveUrlToId(url) {
return urls_1.parseSlashAccountUrl(url, 'gitlab.com');
}
get canonicalUrl() {
return `https://gitlab.com/${this.username}`;
}
getReport(day) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.contributions.has(day)) {
try {
const contributions = yield (yield node_fetch_1.default(`${BASE_URL}/users/${this.username}/calendar.json`)).json();
for (const contributionDate of Object.keys(contributions)) {
const contributionDay = time_1.getDayIndex(M(contributionDate));
this.contributions.set(contributionDay, parseInt(contributions[contributionDate]));
}
if (!this.contributions.has(day)) {
this.contributions.set(day, 0);
}
async getReport(day) {
if (!this.contributions.has(day)) {
try {
const contributions = await (await node_fetch_1.default(`${BASE_URL}/users/${this.username}/calendar.json`)).json();
for (const contributionDate of Object.keys(contributions)) {
const contributionDay = time_1.getDayIndex(M(contributionDate));
this.contributions.set(contributionDay, parseInt(contributions[contributionDate]));
}
catch (_a) {
return null;
if (!this.contributions.has(day)) {
this.contributions.set(day, 0);
}
}
return this.contributions.get(day);
});
catch (_a) {
return null;
}
}
return this.contributions.get(day);
}

@@ -49,0 +39,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_fetch_1 = require("node-fetch");
const chalk_1 = require("chalk");
const M = require("moment");
const node_fetch_1 = require("node-fetch");
const urls_1 = require("../libs/urls");
const time_1 = require("../time");
const urls_1 = require("../libs/urls");
const BASE_URL = 'https://hackerrank.com';

@@ -22,27 +14,26 @@ class HackerRankAccount {

}
get canonicalUrl() {
return `https://hackerrank.com/${this.username}`;
}
static resolveUrlToId(url) {
return urls_1.parseAccountUrl(url, /\/\/(?:www\.)?hackerrank\.com\/(?:profile\/)?([^/\s?]+)/i);
}
get canonicalUrl() {
return `https://hackerrank.com/${this.username}`;
}
getReport(day) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.submissions.has(day)) {
try {
const contributions = yield (yield node_fetch_1.default(`${BASE_URL}/rest/hackers/${this.username}/submission_histories`)).json();
for (const contributionDate of Object.keys(contributions)) {
const contributionDay = time_1.getDayIndex(M(contributionDate));
this.submissions.set(contributionDay, parseInt(contributions[contributionDate]));
}
if (!this.submissions.has(day)) {
this.submissions.set(day, 0);
}
async getReport(day) {
if (!this.submissions.has(day)) {
try {
const url = `${BASE_URL}/rest/hackers/${this.username}/submission_histories`;
const contributions = await (await node_fetch_1.default(url)).json();
for (const contributionDate of Object.keys(contributions)) {
const contributionDay = time_1.getDayIndex(M(contributionDate));
this.submissions.set(contributionDay, parseInt(contributions[contributionDate]));
}
catch (_a) {
return null;
if (!this.submissions.has(day)) {
this.submissions.set(day, 0);
}
}
return this.submissions.get(day);
});
catch (_a) {
return null;
}
}
return this.submissions.get(day);
}

@@ -49,0 +40,0 @@ }

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_fetch_1 = require("node-fetch");
const query_string_1 = require("query-string");
const node_fetch_1 = require("node-fetch");
const time_1 = require("../time");

@@ -21,26 +13,24 @@ const BASE_URL = 'https://api.stackexchange.com/2.2';

}
getReport(day) {
return __awaiter(this, void 0, void 0, function* () {
if (this.reputation.has(day)) {
return this.reputation.get(day);
}
const dayMoment = time_1.parseDayIndex(day);
const url = `${BASE_URL}/users/${this.userId}/reputation?` + query_string_1.stringify({
site: this.site,
fromdate: dayMoment.unix(),
todate: dayMoment.add(1, 'day').unix(),
pagesize: 100
});
try {
const response = (yield (yield node_fetch_1.default(url)).json());
const changes = response.items;
const report = changes.map(item => item.reputation_change || 0)
.reduce((sum, add) => sum + add, 0);
this.reputation.set(day, report);
return report;
}
catch (_a) {
return null;
}
async getReport(day) {
if (this.reputation.has(day)) {
return this.reputation.get(day);
}
const dayMoment = time_1.parseDayIndex(day);
const url = `${BASE_URL}/users/${this.userId}/reputation?` + query_string_1.stringify({
site: this.site,
fromdate: dayMoment.unix(),
todate: dayMoment.add(1, 'day').unix(),
pagesize: 100,
});
try {
const response = (await (await node_fetch_1.default(url)).json());
const changes = response.items;
const report = changes.map((item) => item.reputation_change || 0)
.reduce((sum, add) => sum + add, 0);
this.reputation.set(day, report);
return report;
}
catch (_a) {
return null;
}
}

@@ -47,0 +37,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = require("chalk");
const urls_1 = require("../../libs/urls");
const stackexchange_1 = require("../stackexchange");
const urls_1 = require("../../libs/urls");
class ReverseEngineeringAccount extends stackexchange_1.StackExchangeAccount {

@@ -7,0 +7,0 @@ constructor(userId) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = require("chalk");
const urls_1 = require("../libs/urls");
const stackexchange_1 = require("./stackexchange");
const urls_1 = require("../libs/urls");
class StackOverflowAccount extends stackexchange_1.StackExchangeAccount {

@@ -7,0 +7,0 @@ constructor(userId) {

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs-extra");
const os = require("os");
const fs = require("fs-extra");
const path = require("path");
const chalk_1 = require("chalk");
const M = require("moment");
const node_fetch_1 = require("node-fetch");
const query_string_1 = require("query-string");
const node_fetch_1 = require("node-fetch");
const M = require("moment");
const chalk_1 = require("chalk");
const urls_1 = require("../libs/urls");
const time_1 = require("../time");
const urls_1 = require("../libs/urls");
const BASE_URL = 'https://wakatime.com/api/v1';

@@ -27,50 +19,46 @@ const formatMoment = (moment) => moment.format('YYYY-MM-DD');

}
get canonicalUrl() {
return `https://wakatime.com/@${this.username}`;
}
static resolveUrlToId(url) {
return urls_1.parseSlashAccountUrl(url, 'wakatime.com');
}
get canonicalUrl() {
return `https://wakatime.com/@${this.username}`;
}
getReport(day) {
return __awaiter(this, void 0, void 0, function* () {
if (this.durations.has(day)) {
return this.durations.get(day);
}
this.apiKey = yield this.findApiKey();
if (!this.apiKey) {
return null;
}
const dayMoment = time_1.parseDayIndex(day);
const url = `${BASE_URL}/users/${this.username}/summaries?` + query_string_1.stringify({
start: formatMoment(dayMoment),
end: formatMoment(dayMoment.add(1, 'day')),
api_key: this.apiKey
});
try {
const response = (yield (yield node_fetch_1.default(url)).json());
const seconds = response.data[0].grand_total.total_seconds;
const duration = seconds > 0 ? M.duration(seconds, 'seconds').humanize() : 'no time';
this.durations.set(day, duration);
return duration;
}
catch (_a) {
// `null` will be returned below
}
async getReport(day) {
if (this.durations.has(day)) {
return this.durations.get(day);
}
this.apiKey = await this.findApiKey();
if (!this.apiKey) {
return null;
}
const dayMoment = time_1.parseDayIndex(day);
const url = `${BASE_URL}/users/${this.username}/summaries?` + query_string_1.stringify({
start: formatMoment(dayMoment),
end: formatMoment(dayMoment.add(1, 'day')),
api_key: this.apiKey,
});
try {
const response = (await (await node_fetch_1.default(url)).json());
const seconds = response.data[0].grand_total.total_seconds;
const duration = M.duration(seconds, 'seconds');
this.durations.set(day, duration);
return duration;
}
catch (_a) {
// `null` will be returned below
}
return null;
}
findApiKey() {
return __awaiter(this, void 0, void 0, function* () {
try {
const cfgPath = path.join(os.homedir(), '.wakatime.cfg');
const cfgContent = yield fs.readFile(cfgPath, 'utf8');
const match = cfgContent.match(/api_key ?= ?(.+)/);
if (match && match[1]) {
return match[1];
}
async findApiKey() {
try {
const cfgPath = path.join(os.homedir(), '.wakatime.cfg');
const cfgContent = await fs.readFile(cfgPath, 'utf8');
const match = cfgContent.match(/api_key ?= ?(.+)/);
if (match && match[1]) {
return match[1];
}
catch (_a) {
return null;
}
});
}
catch (_a) {
return null;
}
}

@@ -77,0 +65,0 @@ }

@@ -11,2 +11,3 @@ "use strict";

const args = gar(process.argv.slice(2));
const positionalArgs = args._;
if (Boolean(args.help)) {

@@ -18,2 +19,10 @@ console.log(chalk_1.default `

{blue Display a summary of the current week:}
{dim $} {bold devstats} -w {dim or} {bold devstats} --week
{blue Display a summary of the last {bold <days>} days:}
{dim $} {bold devstats} -d <days> {dim or} {bold devstats} --days <days>
{blue Switch between days interactively:}

@@ -41,8 +50,12 @@

}
else if (args._.length === 0) {
show_1.default({ interactive: Boolean(args.i || args.interactive) });
else if (positionalArgs.length === 0) {
show_1.default({
interactive: Boolean(args.i || args.interactive),
days: Number(args.d || args.days),
week: Boolean(args.w || args.week),
});
}
else {
const command = args._.shift();
const commandArgs = args._;
const command = positionalArgs.shift();
const commandArgs = positionalArgs;
if (command === 'add') {

@@ -49,0 +62,0 @@ add_1.default(commandArgs);

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = require("chalk");
const update_notifier_1 = require("../libs/update-notifier");
const accounts_1 = require("../libs/accounts");
const config_1 = require("../libs/config");
const update_notifier_1 = require("../libs/update-notifier");
function add(args) {

@@ -8,0 +8,0 @@ const accountUrl = accounts_1.resolveAccountArguments(args).canonicalUrl;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = require("chalk");
const update_notifier_1 = require("../libs/update-notifier");
const accounts_1 = require("../libs/accounts");
const config_1 = require("../libs/config");
const update_notifier_1 = require("../libs/update-notifier");
function remove(args) {

@@ -14,3 +14,3 @@ const accountUrl = accounts_1.resolveAccountArguments(args).canonicalUrl;

}
config.set('accounts', accounts.filter(url => url !== accountUrl));
config.set('accounts', accounts.filter((url) => url !== accountUrl));
console.log(chalk_1.default `

@@ -17,0 +17,0 @@ {blue You've successfully removed {bold ${accountUrl}} from your accounts!}

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = require("chalk");
const moment = require("moment");
const chalk_1 = require("chalk");
const Terminal = require("../libs/terminal");
const update_notifier_1 = require("../libs/update-notifier");
const time_1 = require("../time");
const accounts_1 = require("../libs/accounts");
const config_1 = require("../libs/config");
const accounts_1 = require("../libs/accounts");
function show({ interactive }) {
const day_1 = require("../reporters/day");
const days_1 = require("../reporters/days");
const week_1 = require("../reporters/week");
function show({ interactive, days, week }) {
const accounts = config_1.default().get('accounts').map(accounts_1.resolveAccountUrl);

@@ -30,6 +32,9 @@ if (accounts.length === 0) {

}
const todayIndex = time_1.getDayIndex(moment());
let dayIndex = todayIndex;
let dayMoment = time_1.parseDayIndex(dayIndex);
let dayString = dayMoment.format('MMMM Do, YYYY');
let index = 0;
let reportTitle;
const reporter = week ?
new week_1.default()
: (days && days !== 1) ?
new days_1.default(days)
: new day_1.default();
const reports = new Map();

@@ -47,8 +52,8 @@ const { stdin } = process;

// Left arrow key
dayIndex--;
index--;
printDailyReport();
}
else if (key[2] === 'C' && dayIndex < todayIndex) {
else if (key[2] === 'C' && index < 0) {
// Right arrow key
dayIndex++;
index++;
printDailyReport();

@@ -60,20 +65,27 @@ }

function printDailyReport() {
dayMoment = time_1.parseDayIndex(dayIndex);
dayString = dayMoment.format('MMMM Do, YYYY');
const currentDayIndex = dayIndex;
reports.clear();
const currentIndex = index;
reportTitle = reporter.report(index, accounts, (account, report) => {
if (currentIndex === index)
reports.set(account, report);
render();
});
render();
for (const account of accounts) {
account.getReport(currentDayIndex).then(report => {
if (currentDayIndex !== dayIndex)
return;
reports.set(account, report);
render();
});
}
}
function formatDuration(duration) {
return duration.asSeconds ? duration.humanize() : 'no time';
}
function parseReport(report) {
// tslint:disable-next-line:triple-equals
if (report == null)
return;
if (moment.isDuration(report))
return formatDuration(report);
return String(report);
}
function renderReport(account, report) {
const accountType = accounts_1.getAccountType(account);
return report !== undefined && report !== null ?
chalk_1.default `{bold ${report + ''}} ${accountType.statistic}`
const parsedReport = parseReport(report);
return parsedReport ?
chalk_1.default `{bold ${parsedReport}} ${accountType.statistic}`
: chalk_1.default.red('An error occurred.');

@@ -83,3 +95,3 @@ }

let output = '';
output += chalk_1.default `\n{blue Daily report for {bold ${dayString}}}\n`;
output += chalk_1.default `\n{blue ${reportTitle}}\n`;
output += '\n';

@@ -90,3 +102,6 @@ for (const account of accounts) {

const report = reports.get(account);
output += chalk_1.default ` {inverse ${theme(' ')}}${chalk_1.default.reset(' ')}${theme(title.padEnd(15))}${renderReport(account, report)}\n`;
output += chalk_1.default ` {inverse ${theme(' ')}}`;
output += chalk_1.default `${chalk_1.default.reset(' ')}`;
output += chalk_1.default `${theme(title.padEnd(15))}`;
output += chalk_1.default `${renderReport(account, report)}\n`;
}

@@ -98,5 +113,10 @@ else {

if (interactive) {
output += chalk_1.default `
{blue {dim [}{bold ←} Previous day{dim ]} ${(dayIndex < todayIndex ? chalk_1.default.blue : chalk_1.default.gray)(chalk_1.default `{dim [}{bold →} Next day{dim ]}`)} {dim [}{bold Q} Quit{dim ]}}
`;
output += '\n';
const buttons = [
chalk_1.default `{blue {dim [}{bold ←} ${reporter.previousLabel}{dim ]}}`,
(index < 0 ? chalk_1.default.blue : chalk_1.default.gray)(chalk_1.default `{dim [}{bold →} ${reporter.nextLabel}{dim ]}`),
chalk_1.default `{blue {dim [}{bold Q} Quit{dim ]}}`,
];
output += buttons.join(' ');
output += '\n';
}

@@ -103,0 +123,0 @@ output += '\n';

{
"name": "devstats",
"version": "1.2.1",
"version": "1.3.0",
"description": "A CLI application that fetches stats from developer sites.",

@@ -15,10 +15,20 @@ "author": "Niklas Higi <niklas@shroudedcode.com> (https://shroudedcode.com/)",

"scripts": {
"test": "true",
"build": "tsc",
"watch": "tsc -w",
"release": "rm -rf dist; tsc --sourceMap false; np"
"release": "rm -rf dist && tsc --sourceMap false && np"
},
"dependencies": {
"chalk": "^2.4.1",
"conf": "^5.0.0",
"fs-extra": "^8.1.0",
"gar": "^1.0.3",
"jsdom": "^15.0.0",
"moment": "^2.22.2",
"node-fetch": "^2.2.0",
"query-string": "^6.1.0",
"update-notifier": "^3.0.1"
},
"devDependencies": {
"@types/conf": "^1.4.0",
"@types/fs-extra": "^5.0.4",
"@types/conf": "^3.0.0",
"@types/fs-extra": "^8.0.0",
"@types/jsdom": "^12.2.0",

@@ -29,20 +39,8 @@ "@types/node": "^10.9.4",

"@types/update-notifier": "^2.2.0",
"@types/yargs": "^12.0.1",
"np": "^3.0.4",
"ts-loader": "^5.3.0",
"@types/yargs": "^13.0.0",
"np": "^5.0.3",
"ts-loader": "^6.0.4",
"tslint": "^5.11.0",
"tslint-xo": "^0.9.0",
"typescript": "^3.0.3"
},
"dependencies": {
"chalk": "^2.4.1",
"conf": "^2.0.0",
"fs-extra": "^7.0.0",
"gar": "^1.0.3",
"jsdom": "^13.0.0",
"moment": "^2.22.2",
"node-fetch": "^2.2.0",
"query-string": "^6.1.0",
"update-notifier": "^2.5.0"
}
}

@@ -7,8 +7,6 @@ # devstats

[![][npm-badge]][npm-link]
[![](https://img.shields.io/npm/v/devstats.svg)](https://www.npmjs.com/package/devstats)
**devstats** is a CLI application written in TypeScript that fetches statistics from developer sites like StackOverflow, WakaTime, and GitHub and displays them nicely.
DevStats is a CLI application written in TypeScript that fetches statistics from "developer sites" like StackOverflow, WakaTime and GitHub and displays them nicely.
## Installation

@@ -57,2 +55,10 @@

Display a summary of the current week:
$ devstats -w or devstats --week
Display a summary of the last <days> days:
$ devstats -d <days> or devstats --days <days>
Switch between days interactively:

@@ -62,9 +68,15 @@

Add a new account through its URL:
Add an account:
$ devstats add <site> <username/user-id>
$ devstats add github shroudedcode
$ devstats add <url>
$ devstats add https://github.com/shroudedcode
Remove an account through its URL:
Remove an account:
$ devstats remove <site> <username/user-id>
$ devstats remove stackoverflow 6662225
$ devstats remove <url>

@@ -91,1 +103,4 @@ $ devstats remove https://stackoverflow.com/users/6662225

MIT © [Niklas Higi](https://shroudedcode.com)
[npm-link]: https://www.npmjs.com/package/devstats
[npm-badge]: https://img.shields.io/npm/v/devstats.svg?style=flat-square

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc