mirror of
https://github.com/badges/shields.git
synced 2025-04-18 19:44:04 +03:00
Add renderDateBadge helper; affects [aur BitbucketLastCommit chrome date eclipse factorio galaxytoolshed GiteaLastCommit GistLastCommit GithubCreatedAt GithubHacktoberfest GithubIssueDetail GithubLastCommit GithubReleaseDate GitlabLastCommit maven npm openvsx snapcraft SourceforgeLastCommit steam vaadin visualstudio wordpress] (#10682)
* add and consistently use parseDate and renderDateBadge helpers also move - age - formatDate - formatRelativeDate to date.js * fix bug in wordpress last update badge * validate in formatDate() and age() it is going to be unlikely we'll invoke either of these directly now, but lets calidate here too * remove unusued imports * reverse colours for galaxy toolshed
This commit is contained in:
parent
4132ca2e7e
commit
5cdef88bcc
@ -1,10 +1,8 @@
|
||||
import Joi from 'joi'
|
||||
import {
|
||||
floorCount as floorCountColor,
|
||||
age as ageColor,
|
||||
} from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { floorCount as floorCountColor } from '../color-formatters.js'
|
||||
import { renderLicenseBadge } from '../licenses.js'
|
||||
import { metric, formatDate } from '../text-formatters.js'
|
||||
import { metric } from '../text-formatters.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import {
|
||||
BaseJsonService,
|
||||
@ -243,16 +241,10 @@ class AurLastModified extends BaseAurService {
|
||||
|
||||
static defaultBadgeData = { label: 'last modified' }
|
||||
|
||||
static render({ date }) {
|
||||
const color = ageColor(date)
|
||||
const message = formatDate(date)
|
||||
return { color, message }
|
||||
}
|
||||
|
||||
async handle({ packageName }) {
|
||||
const json = await this.fetch({ packageName })
|
||||
const date = 1000 * parseInt(json.results[0].LastModified)
|
||||
return this.constructor.render({ date })
|
||||
return renderDateBadge(date)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { BaseJsonService, NotFound, pathParam, queryParam } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { relativeUri } from '../validators.js'
|
||||
|
||||
const schema = Joi.object({
|
||||
@ -43,13 +42,6 @@ export default class BitbucketLastCommit extends BaseJsonService {
|
||||
|
||||
static defaultBadgeData = { label: 'last commit' }
|
||||
|
||||
static render({ commitDate }) {
|
||||
return {
|
||||
message: formatDate(commitDate),
|
||||
color: ageColor(Date.parse(commitDate)),
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ user, repo, branch, path }) {
|
||||
// https://developer.atlassian.com/cloud/bitbucket/rest/api-group-commits/#api-repositories-workspace-repo-slug-commits-get
|
||||
return this._requestJson({
|
||||
@ -76,6 +68,6 @@ export default class BitbucketLastCommit extends BaseJsonService {
|
||||
|
||||
if (!commit) throw new NotFound({ prettyMessage: 'no commits found' })
|
||||
|
||||
return this.constructor.render({ commitDate: commit.date })
|
||||
return renderDateBadge(commit.date)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { age } from '../color-formatters.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { NotFound, pathParams } from '../index.js'
|
||||
import BaseChromeWebStoreService from './chrome-web-store-base.js'
|
||||
|
||||
@ -31,11 +30,6 @@ export default class ChromeWebStoreLastUpdated extends BaseChromeWebStoreService
|
||||
throw new NotFound({ prettyMessage: 'not found' })
|
||||
}
|
||||
|
||||
const lastUpdatedDate = Date.parse(lastUpdated)
|
||||
|
||||
return {
|
||||
message: formatDate(lastUpdatedDate),
|
||||
color: age(lastUpdatedDate),
|
||||
}
|
||||
return renderDateBadge(lastUpdated)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
import pep440 from '@renovatebot/pep440'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
/**
|
||||
* Determines the color used for a badge based on version.
|
||||
@ -175,24 +174,7 @@ function colorScale(steps, colors, reversed) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the color used for a badge according to the age.
|
||||
* Age is calculated as days elapsed till current date.
|
||||
* The color varies from bright green to red as the age increases
|
||||
* or the other way around if `reverse` is given `true`.
|
||||
*
|
||||
* @param {string} date Date string
|
||||
* @param {boolean} reversed Reverse the color scale a.k.a. the older, the better
|
||||
* @returns {string} Badge color
|
||||
*/
|
||||
function age(date, reversed = false) {
|
||||
const colorByAge = colorScale([7, 30, 180, 365, 730], undefined, !reversed)
|
||||
const daysElapsed = dayjs().diff(dayjs(date), 'days')
|
||||
return colorByAge(daysElapsed)
|
||||
}
|
||||
|
||||
export {
|
||||
age,
|
||||
colorScale,
|
||||
coveragePercentage,
|
||||
downloadCount,
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { expect } from 'chai'
|
||||
import { forCases, given, test } from 'sazerac'
|
||||
import {
|
||||
age,
|
||||
colorScale,
|
||||
coveragePercentage,
|
||||
letterScore,
|
||||
@ -53,46 +52,6 @@ describe('Color formatters', function () {
|
||||
given('Z').expect('red')
|
||||
})
|
||||
|
||||
const monthsAgo = months => {
|
||||
const result = new Date()
|
||||
// This looks wack but it works.
|
||||
result.setMonth(result.getMonth() - months)
|
||||
return result
|
||||
}
|
||||
test(age, () => {
|
||||
given(Date.now())
|
||||
.describe('when given the current timestamp')
|
||||
.expect('brightgreen')
|
||||
given(new Date())
|
||||
.describe('when given the current Date')
|
||||
.expect('brightgreen')
|
||||
given(new Date(2001, 1, 1))
|
||||
.describe('when given a Date many years ago')
|
||||
.expect('red')
|
||||
given(monthsAgo(2))
|
||||
.describe('when given a Date two months ago')
|
||||
.expect('yellowgreen')
|
||||
given(monthsAgo(15))
|
||||
.describe('when given a Date 15 months ago')
|
||||
.expect('orange')
|
||||
// --- reversed --- //
|
||||
given(Date.now(), true)
|
||||
.describe('when given the current timestamp and reversed')
|
||||
.expect('red')
|
||||
given(new Date(), true)
|
||||
.describe('when given the current Date and reversed')
|
||||
.expect('red')
|
||||
given(new Date(2001, 1, 1), true)
|
||||
.describe('when given a Date many years ago and reversed')
|
||||
.expect('brightgreen')
|
||||
given(monthsAgo(2), true)
|
||||
.describe('when given a Date two months ago and reversed')
|
||||
.expect('yellow')
|
||||
given(monthsAgo(15), true)
|
||||
.describe('when given a Date 15 months ago and reversed')
|
||||
.expect('green')
|
||||
})
|
||||
|
||||
test(version, () => {
|
||||
forCases([given('1.0'), given(9), given(1.0)]).expect('blue')
|
||||
|
||||
|
108
services/date.js
Normal file
108
services/date.js
Normal file
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Commonly-used functions for rendering badges containing a date
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import dayjs from 'dayjs'
|
||||
import calendar from 'dayjs/plugin/calendar.js'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat.js'
|
||||
import { colorScale } from './color-formatters.js'
|
||||
import { InvalidResponse } from './index.js'
|
||||
|
||||
dayjs.extend(calendar)
|
||||
dayjs.extend(customParseFormat)
|
||||
|
||||
/**
|
||||
* Parse and validate a string date into a dayjs object. Use this helper
|
||||
* in preference to invoking dayjs directly when parsing a date from string.
|
||||
*
|
||||
* @param {...any} args - Variadic: Arguments to pass through to dayjs
|
||||
* @returns {dayjs} - Parsed object
|
||||
* @throws {InvalidResponse} - Error if validation fails
|
||||
* @see https://day.js.org/docs/en/parse/string
|
||||
* @see https://day.js.org/docs/en/parse/string-format
|
||||
* @see https://day.js.org/docs/en/parse/is-valid
|
||||
* @example
|
||||
* parseDate('2024-01-01')
|
||||
* parseDate('31/01/2024', 'DD/MM/YYYY')
|
||||
* parseDate('2018 Enero 15', 'YYYY MMMM DD', 'es')
|
||||
*/
|
||||
function parseDate(...args) {
|
||||
let date
|
||||
if (args.length >= 2) {
|
||||
// always use strict mode if format arg is supplied
|
||||
date = dayjs(...args, true)
|
||||
} else {
|
||||
date = dayjs(...args)
|
||||
}
|
||||
if (!date.isValid()) {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid date' })
|
||||
}
|
||||
return date
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted date string without the year based on the value of input date param d.
|
||||
*
|
||||
* @param {Date | string | number | dayjs } d JS Date object, string, unix timestamp or dayjs object
|
||||
* @returns {string} Formatted date string
|
||||
*/
|
||||
function formatDate(d) {
|
||||
const date = parseDate(d)
|
||||
const dateString = date.calendar(null, {
|
||||
lastDay: '[yesterday]',
|
||||
sameDay: '[today]',
|
||||
lastWeek: '[last] dddd',
|
||||
sameElse: 'MMMM YYYY',
|
||||
})
|
||||
// Trim current year from date string
|
||||
return dateString.replace(` ${dayjs().year()}`, '').toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the color used for a badge according to the age.
|
||||
* Age is calculated as days elapsed till current date.
|
||||
* The color varies from bright green to red as the age increases
|
||||
* or the other way around if `reverse` is given `true`.
|
||||
*
|
||||
* @param {Date | string | number | dayjs } date JS Date object, string, unix timestamp or dayjs object
|
||||
* @param {boolean} reversed Reverse the color scale (the older, the better)
|
||||
* @returns {string} Badge color
|
||||
*/
|
||||
function age(date, reversed = false) {
|
||||
const colorByAge = colorScale([7, 30, 180, 365, 730], undefined, !reversed)
|
||||
const daysElapsed = dayjs().diff(parseDate(date), 'days')
|
||||
return colorByAge(daysElapsed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a badge object that displays a date
|
||||
*
|
||||
* @param {Date | string | number | dayjs } date JS Date object, string, unix timestamp or dayjs object
|
||||
* @param {boolean} reversed Reverse the color scale (the older, the better)
|
||||
* @returns {object} A badge object that has two properties: message, and color
|
||||
*/
|
||||
function renderDateBadge(date, reversed = false) {
|
||||
const d = parseDate(date)
|
||||
const color = age(d, reversed)
|
||||
const message = formatDate(d)
|
||||
return { message, color }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a relative date from the input timestamp.
|
||||
* For example, day after tomorrow's timestamp will return 'in 2 days'.
|
||||
*
|
||||
* @param {number | string} timestamp - Unix timestamp
|
||||
* @returns {string} Relative date from the unix timestamp
|
||||
*/
|
||||
function formatRelativeDate(timestamp) {
|
||||
const parsedDate = dayjs.unix(parseInt(timestamp, 10))
|
||||
if (!parsedDate.isValid()) {
|
||||
return 'invalid date'
|
||||
}
|
||||
return dayjs().to(parsedDate).toLowerCase()
|
||||
}
|
||||
|
||||
export { parseDate, renderDateBadge, formatDate, formatRelativeDate, age }
|
132
services/date.spec.js
Normal file
132
services/date.spec.js
Normal file
@ -0,0 +1,132 @@
|
||||
import { expect } from 'chai'
|
||||
import { test, given } from 'sazerac'
|
||||
import sinon from 'sinon'
|
||||
import { parseDate, formatDate, formatRelativeDate, age } from './date.js'
|
||||
import { InvalidResponse } from './index.js'
|
||||
|
||||
describe('parseDate', function () {
|
||||
it('parses valid inputs', function () {
|
||||
expect(parseDate('2024-01-01').valueOf()).to.equal(
|
||||
new Date('2024-01-01').valueOf(),
|
||||
)
|
||||
expect(parseDate('Jan 01 01:00:00 2024 GMT').valueOf()).to.equal(
|
||||
new Date('2024-01-01T01:00:00.000Z').valueOf(),
|
||||
)
|
||||
expect(parseDate('31/01/2024', 'DD/MM/YYYY').valueOf()).to.equal(
|
||||
new Date('2024-01-31T00:00:00.000Z').valueOf(),
|
||||
)
|
||||
})
|
||||
|
||||
it('throws when given invalid inputs', function () {
|
||||
// not a date
|
||||
expect(() => parseDate('foo')).to.throw(InvalidResponse)
|
||||
expect(() => parseDate([])).to.throw(InvalidResponse)
|
||||
expect(() => parseDate(null)).to.throw(InvalidResponse)
|
||||
|
||||
// invalid dates (only works with format string)
|
||||
expect(() => parseDate('2024-02-31', 'YYYY-MM-DD')).to.throw(
|
||||
InvalidResponse,
|
||||
)
|
||||
expect(() => parseDate('2024-12-32', 'YYYY-MM-DD')).to.throw(
|
||||
InvalidResponse,
|
||||
)
|
||||
|
||||
// non-standard format with no format string
|
||||
expect(() => parseDate('31/01/2024')).to.throw(InvalidResponse)
|
||||
|
||||
// parse format doesn't match date
|
||||
expect(() => parseDate('2024-01-01', 'YYYYMMDDHHmmss')).to.throw(
|
||||
InvalidResponse,
|
||||
)
|
||||
})
|
||||
|
||||
test(formatDate, () => {
|
||||
given(1465513200000)
|
||||
.describe('when given a timestamp in june 2016')
|
||||
.expect('june 2016')
|
||||
})
|
||||
|
||||
context('in october', function () {
|
||||
let clock
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(new Date(2017, 9, 15).getTime())
|
||||
})
|
||||
afterEach(function () {
|
||||
clock.restore()
|
||||
})
|
||||
|
||||
test(formatDate, () => {
|
||||
given(new Date(2017, 0, 1).getTime())
|
||||
.describe('when given the beginning of this year')
|
||||
.expect('january')
|
||||
})
|
||||
})
|
||||
|
||||
context('in october', function () {
|
||||
let clock
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(new Date(2018, 9, 29).getTime())
|
||||
})
|
||||
afterEach(function () {
|
||||
clock.restore()
|
||||
})
|
||||
|
||||
test(formatRelativeDate, () => {
|
||||
given(new Date(2018, 9, 31).getTime() / 1000)
|
||||
.describe('when given the end of october')
|
||||
.expect('in 2 days')
|
||||
})
|
||||
|
||||
test(formatRelativeDate, () => {
|
||||
given(new Date(2018, 9, 1).getTime() / 1000)
|
||||
.describe('when given the beginning of october')
|
||||
.expect('a month ago')
|
||||
})
|
||||
|
||||
test(formatRelativeDate, () => {
|
||||
given(9999999999999)
|
||||
.describe('when given invalid date')
|
||||
.expect('invalid date')
|
||||
})
|
||||
})
|
||||
|
||||
const monthsAgo = months => {
|
||||
const result = new Date()
|
||||
// This looks wack but it works.
|
||||
result.setMonth(result.getMonth() - months)
|
||||
return result
|
||||
}
|
||||
test(age, () => {
|
||||
given(Date.now())
|
||||
.describe('when given the current timestamp')
|
||||
.expect('brightgreen')
|
||||
given(new Date())
|
||||
.describe('when given the current Date')
|
||||
.expect('brightgreen')
|
||||
given(new Date(2001, 1, 1))
|
||||
.describe('when given a Date many years ago')
|
||||
.expect('red')
|
||||
given(monthsAgo(2))
|
||||
.describe('when given a Date two months ago')
|
||||
.expect('yellowgreen')
|
||||
given(monthsAgo(15))
|
||||
.describe('when given a Date 15 months ago')
|
||||
.expect('orange')
|
||||
// --- reversed --- //
|
||||
given(Date.now(), true)
|
||||
.describe('when given the current timestamp and reversed')
|
||||
.expect('red')
|
||||
given(new Date(), true)
|
||||
.describe('when given the current Date and reversed')
|
||||
.expect('red')
|
||||
given(new Date(2001, 1, 1), true)
|
||||
.describe('when given a Date many years ago and reversed')
|
||||
.expect('brightgreen')
|
||||
given(monthsAgo(2), true)
|
||||
.describe('when given a Date two months ago and reversed')
|
||||
.expect('yellow')
|
||||
given(monthsAgo(15), true)
|
||||
.describe('when given a Date 15 months ago and reversed')
|
||||
.expect('green')
|
||||
})
|
||||
})
|
@ -1,4 +1,4 @@
|
||||
import { formatRelativeDate } from '../text-formatters.js'
|
||||
import { formatRelativeDate } from '../date.js'
|
||||
import { BaseService, pathParams } from '../index.js'
|
||||
|
||||
const description = `
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { pathParams } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import EclipseMarketplaceBase from './eclipse-marketplace-base.js'
|
||||
|
||||
@ -34,19 +33,12 @@ export default class EclipseMarketplaceUpdate extends EclipseMarketplaceBase {
|
||||
|
||||
static defaultBadgeData = { label: 'updated' }
|
||||
|
||||
static render({ date }) {
|
||||
return {
|
||||
message: formatDate(date),
|
||||
color: ageColor(date),
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ name }) {
|
||||
const { marketplace } = await this.fetch({
|
||||
name,
|
||||
schema: updateResponseSchema,
|
||||
})
|
||||
const date = 1000 * parseInt(marketplace.node.changed)
|
||||
return this.constructor.render({ date })
|
||||
return renderDateBadge(date)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { BaseJsonService, pathParams } from '../index.js'
|
||||
import { age } from '../color-formatters.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { renderDownloadsBadge } from '../downloads.js'
|
||||
import { renderVersionBadge } from '../version.js'
|
||||
@ -131,18 +130,9 @@ class FactorioModPortalLastUpdated extends BaseFactorioModPortalService {
|
||||
|
||||
static defaultBadgeData = { label: 'last updated' }
|
||||
|
||||
static render({ lastUpdated }) {
|
||||
return {
|
||||
message: formatDate(lastUpdated),
|
||||
color: age(lastUpdated),
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ modName }) {
|
||||
const resp = await this.fetch({ modName })
|
||||
return this.constructor.render({
|
||||
lastUpdated: resp.latest_release.released_at,
|
||||
})
|
||||
return renderDateBadge(resp.latest_release.released_at)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { pathParams } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import BaseGalaxyToolshedService from './galaxytoolshed-base.js'
|
||||
|
||||
export default class GalaxyToolshedCreatedDate extends BaseGalaxyToolshedService {
|
||||
@ -29,11 +29,6 @@ export default class GalaxyToolshedCreatedDate extends BaseGalaxyToolshedService
|
||||
|
||||
static defaultBadgeData = {
|
||||
label: 'created date',
|
||||
color: 'blue',
|
||||
}
|
||||
|
||||
static render({ date }) {
|
||||
return { message: formatDate(date) }
|
||||
}
|
||||
|
||||
async handle({ repository, owner }) {
|
||||
@ -42,6 +37,6 @@ export default class GalaxyToolshedCreatedDate extends BaseGalaxyToolshedService
|
||||
owner,
|
||||
})
|
||||
const { create_time: date } = response[0]
|
||||
return this.constructor.render({ date })
|
||||
return renderDateBadge(date, true)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { pathParam, queryParam } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { optionalUrl, relativeUri } from '../validators.js'
|
||||
import GiteaBase from './gitea-base.js'
|
||||
import { description, httpErrorsFor } from './gitea-helper.js'
|
||||
@ -114,13 +113,6 @@ export default class GiteaLastCommit extends GiteaBase {
|
||||
|
||||
static defaultBadgeData = { label: 'last commit' }
|
||||
|
||||
static render({ commitDate }) {
|
||||
return {
|
||||
message: formatDate(commitDate),
|
||||
color: ageColor(Date.parse(commitDate)),
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ user, repo, branch, baseUrl, path }) {
|
||||
// https://gitea.com/api/swagger#/repository
|
||||
return super.fetch({
|
||||
@ -146,8 +138,6 @@ export default class GiteaLastCommit extends GiteaBase {
|
||||
baseUrl,
|
||||
path,
|
||||
})
|
||||
return this.constructor.render({
|
||||
commitDate: body[0].commit[displayTimestamp].date,
|
||||
})
|
||||
return renderDateBadge(body[0].commit[displayTimestamp].date)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { pathParams } from '../../index.js'
|
||||
import { formatDate } from '../../text-formatters.js'
|
||||
import { age as ageColor } from '../../color-formatters.js'
|
||||
import { renderDateBadge } from '../../date.js'
|
||||
import { GithubAuthV3Service } from '../github-auth-service.js'
|
||||
import { documentation, httpErrorsFor } from '../github-helpers.js'
|
||||
|
||||
@ -27,13 +26,6 @@ export default class GistLastCommit extends GithubAuthV3Service {
|
||||
|
||||
static defaultBadgeData = { label: 'last commit' }
|
||||
|
||||
static render({ commitDate }) {
|
||||
return {
|
||||
message: formatDate(commitDate),
|
||||
color: ageColor(Date.parse(commitDate)),
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ gistId }) {
|
||||
return this._requestJson({
|
||||
url: `/gists/${gistId}`,
|
||||
@ -44,6 +36,6 @@ export default class GistLastCommit extends GithubAuthV3Service {
|
||||
|
||||
async handle({ gistId }) {
|
||||
const { updated_at: commitDate } = await this.fetch({ gistId })
|
||||
return this.constructor.render({ commitDate })
|
||||
return renderDateBadge(commitDate)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
import dayjs from 'dayjs'
|
||||
import Joi from 'joi'
|
||||
import { age } from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { pathParams } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { GithubAuthV3Service } from './github-auth-service.js'
|
||||
import { documentation, httpErrorsFor } from './github-helpers.js'
|
||||
|
||||
@ -34,14 +32,6 @@ export default class GithubCreatedAt extends GithubAuthV3Service {
|
||||
|
||||
static defaultBadgeData = { label: 'created at' }
|
||||
|
||||
static render({ createdAt }) {
|
||||
const date = dayjs(createdAt)
|
||||
return {
|
||||
message: formatDate(date),
|
||||
color: age(date, true),
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ user, repo }) {
|
||||
const { created_at: createdAt } = await this._requestJson({
|
||||
schema,
|
||||
@ -49,6 +39,6 @@ export default class GithubCreatedAt extends GithubAuthV3Service {
|
||||
httpErrors: httpErrorsFor('repo not found'),
|
||||
})
|
||||
|
||||
return this.constructor.render({ createdAt })
|
||||
return renderDateBadge(createdAt, true)
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import gql from 'graphql-tag'
|
||||
import Joi from 'joi'
|
||||
import dayjs from 'dayjs'
|
||||
import { pathParam, queryParam } from '../index.js'
|
||||
import { parseDate } from '../date.js'
|
||||
import { metric, maybePluralize } from '../text-formatters.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { GithubAuthV4Service } from './github-auth-service.js'
|
||||
@ -97,7 +98,7 @@ export default class GithubHacktoberfestCombinedStatus extends GithubAuthV4Servi
|
||||
// The global cutoff time is 11/1 noon UTC.
|
||||
// https://github.com/badges/shields/pull/4109#discussion_r330782093
|
||||
// We want to show "1 day left" on the last day so we add 1.
|
||||
daysLeft = dayjs(`${year}-11-01 12:00:00 Z`).diff(dayjs(), 'days') + 1
|
||||
daysLeft = parseDate(`${year}-11-01 12:00:00 Z`).diff(dayjs(), 'days') + 1
|
||||
}
|
||||
if (daysLeft < 0) {
|
||||
return {
|
||||
@ -181,7 +182,10 @@ export default class GithubHacktoberfestCombinedStatus extends GithubAuthV4Servi
|
||||
}
|
||||
|
||||
static getCalendarPosition(year) {
|
||||
const daysToStart = dayjs(`${year}-10-01 00:00:00 Z`).diff(dayjs(), 'days')
|
||||
const daysToStart = parseDate(`${year}-10-01 00:00:00 Z`).diff(
|
||||
dayjs(),
|
||||
'days',
|
||||
)
|
||||
const isBefore = daysToStart > 0
|
||||
return { daysToStart, isBefore }
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Joi from 'joi'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { formatDate, metric } from '../text-formatters.js'
|
||||
import { age } from '../color-formatters.js'
|
||||
import { metric } from '../text-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { InvalidResponse, pathParams } from '../index.js'
|
||||
import { GithubAuthV3Service } from './github-auth-service.js'
|
||||
import {
|
||||
@ -133,11 +133,13 @@ const ageUpdateMap = {
|
||||
}).required(),
|
||||
transform: ({ json, property }) =>
|
||||
property === 'age' ? json.created_at : json.updated_at,
|
||||
render: ({ property, value }) => ({
|
||||
color: age(value),
|
||||
label: property === 'age' ? 'created' : 'updated',
|
||||
message: formatDate(value),
|
||||
}),
|
||||
render: ({ property, value }) => {
|
||||
const label = property === 'age' ? 'created' : 'updated'
|
||||
return {
|
||||
...renderDateBadge(value),
|
||||
label,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const milestoneMap = {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { expect } from 'chai'
|
||||
import { test, given } from 'sazerac'
|
||||
import { age } from '../color-formatters.js'
|
||||
import { formatDate, metric } from '../text-formatters.js'
|
||||
import { age, formatDate } from '../date.js'
|
||||
import { metric } from '../text-formatters.js'
|
||||
import { InvalidResponse } from '../index.js'
|
||||
import GithubIssueDetail from './github-issue-detail.service.js'
|
||||
import { issueStateColor, commentsColor } from './github-helpers.js'
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { NotFound, pathParam, queryParam } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { relativeUri } from '../validators.js'
|
||||
import { GithubAuthV3Service } from './github-auth-service.js'
|
||||
import { documentation, httpErrorsFor } from './github-helpers.js'
|
||||
@ -88,13 +87,6 @@ export default class GithubLastCommit extends GithubAuthV3Service {
|
||||
|
||||
static defaultBadgeData = { label: 'last commit' }
|
||||
|
||||
static render({ commitDate }) {
|
||||
return {
|
||||
message: formatDate(commitDate),
|
||||
color: ageColor(Date.parse(commitDate)),
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ user, repo, branch, path }) {
|
||||
return this._requestJson({
|
||||
url: `/repos/${user}/${repo}/commits`,
|
||||
@ -111,8 +103,6 @@ export default class GithubLastCommit extends GithubAuthV3Service {
|
||||
|
||||
if (!commit) throw new NotFound({ prettyMessage: 'no commits found' })
|
||||
|
||||
return this.constructor.render({
|
||||
commitDate: commit[displayTimestamp].date,
|
||||
})
|
||||
return renderDateBadge(commit[displayTimestamp].date)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
import dayjs from 'dayjs'
|
||||
import Joi from 'joi'
|
||||
import { pathParam, queryParam } from '../index.js'
|
||||
import { age } from '../color-formatters.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { GithubAuthV3Service } from './github-auth-service.js'
|
||||
import { documentation, httpErrorsFor } from './github-helpers.js'
|
||||
|
||||
@ -63,14 +61,6 @@ export default class GithubReleaseDate extends GithubAuthV3Service {
|
||||
|
||||
static defaultBadgeData = { label: 'release date' }
|
||||
|
||||
static render({ date }) {
|
||||
const releaseDate = dayjs(date)
|
||||
return {
|
||||
message: formatDate(releaseDate),
|
||||
color: age(releaseDate),
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ variant, user, repo }) {
|
||||
const url =
|
||||
variant === 'release-date'
|
||||
@ -86,10 +76,8 @@ export default class GithubReleaseDate extends GithubAuthV3Service {
|
||||
async handle({ variant, user, repo }, queryParams) {
|
||||
const body = await this.fetch({ variant, user, repo })
|
||||
if (Array.isArray(body)) {
|
||||
return this.constructor.render({
|
||||
date: body[0][queryParams.display_date],
|
||||
})
|
||||
return renderDateBadge(body[0][queryParams.display_date])
|
||||
}
|
||||
return this.constructor.render({ date: body[queryParams.display_date] })
|
||||
return renderDateBadge(body[queryParams.display_date])
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { NotFound, pathParam, queryParam } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { optionalUrl, relativeUri } from '../validators.js'
|
||||
import GitLabBase from './gitlab-base.js'
|
||||
import { description, httpErrorsFor } from './gitlab-helper.js'
|
||||
@ -66,13 +65,6 @@ export default class GitlabLastCommit extends GitLabBase {
|
||||
|
||||
static defaultBadgeData = { label: 'last commit' }
|
||||
|
||||
static render({ commitDate }) {
|
||||
return {
|
||||
message: formatDate(commitDate),
|
||||
color: ageColor(Date.parse(commitDate)),
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ project, baseUrl, ref, path }) {
|
||||
// https://docs.gitlab.com/ee/api/commits.html#list-repository-commits
|
||||
return super.fetch({
|
||||
@ -94,6 +86,6 @@ export default class GitlabLastCommit extends GitLabBase {
|
||||
|
||||
if (!commit) throw new NotFound({ prettyMessage: 'no commits found' })
|
||||
|
||||
return this.constructor.render({ commitDate: commit.committed_date })
|
||||
return renderDateBadge(commit.committed_date)
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,8 @@
|
||||
import Joi from 'joi'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat.js'
|
||||
import dayjs from 'dayjs'
|
||||
import { InvalidResponse, pathParams } from '../index.js'
|
||||
import { pathParams } from '../index.js'
|
||||
import { parseDate, renderDateBadge } from '../date.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import MavenCentralBase from './maven-central-base.js'
|
||||
dayjs.extend(customParseFormat)
|
||||
|
||||
const updateResponseSchema = Joi.object({
|
||||
metadata: Joi.object({
|
||||
@ -38,13 +34,6 @@ export default class MavenCentralLastUpdate extends MavenCentralBase {
|
||||
|
||||
static defaultBadgeData = { label: 'last updated' }
|
||||
|
||||
static render({ date }) {
|
||||
return {
|
||||
message: formatDate(date),
|
||||
color: ageColor(date),
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ groupId, artifactId }) {
|
||||
const { metadata } = await this.fetch({
|
||||
groupId,
|
||||
@ -52,15 +41,11 @@ export default class MavenCentralLastUpdate extends MavenCentralBase {
|
||||
schema: updateResponseSchema,
|
||||
})
|
||||
|
||||
const date = dayjs(
|
||||
const date = parseDate(
|
||||
String(metadata.versioning.lastUpdated),
|
||||
'YYYYMMDDHHmmss',
|
||||
)
|
||||
|
||||
if (!date.isValid) {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid date' })
|
||||
}
|
||||
|
||||
return this.constructor.render({ date })
|
||||
return renderDateBadge(date)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import dayjs from 'dayjs'
|
||||
import { InvalidResponse, NotFound, pathParam, queryParam } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { NotFound, pathParam, queryParam } from '../index.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import NpmBase, {
|
||||
packageNameDescription,
|
||||
queryParamSchema,
|
||||
@ -21,26 +19,17 @@ const abbreviatedSchema = Joi.object({
|
||||
modified: Joi.string().required(),
|
||||
}).required()
|
||||
|
||||
class NpmLastUpdateBase extends NpmBase {
|
||||
export class NpmLastUpdateWithTag extends NpmBase {
|
||||
static category = 'activity'
|
||||
|
||||
static defaultBadgeData = { label: 'last updated' }
|
||||
|
||||
static render({ date }) {
|
||||
return {
|
||||
message: formatDate(date),
|
||||
color: ageColor(date),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class NpmLastUpdateWithTag extends NpmLastUpdateBase {
|
||||
static route = {
|
||||
base: 'npm/last-update',
|
||||
pattern: ':scope(@[^/]+)?/:packageName/:tag',
|
||||
queryParamSchema,
|
||||
}
|
||||
|
||||
static defaultBadgeData = { label: 'last updated' }
|
||||
|
||||
static openApi = {
|
||||
'/npm/last-update/{packageName}/{tag}': {
|
||||
get: {
|
||||
@ -81,19 +70,17 @@ export class NpmLastUpdateWithTag extends NpmLastUpdateBase {
|
||||
throw new NotFound({ prettyMessage: 'tag not found' })
|
||||
}
|
||||
|
||||
const date = dayjs(packageData.time[tagVersion])
|
||||
|
||||
if (!date.isValid) {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid date' })
|
||||
}
|
||||
|
||||
return this.constructor.render({ date })
|
||||
return renderDateBadge(packageData.time[tagVersion])
|
||||
}
|
||||
}
|
||||
|
||||
export class NpmLastUpdate extends NpmLastUpdateBase {
|
||||
export class NpmLastUpdate extends NpmBase {
|
||||
static category = 'activity'
|
||||
|
||||
static route = this.buildRoute('npm/last-update', { withTag: false })
|
||||
|
||||
static defaultBadgeData = { label: 'last updated' }
|
||||
|
||||
static openApi = {
|
||||
'/npm/last-update/{packageName}': {
|
||||
get: {
|
||||
@ -127,12 +114,6 @@ export class NpmLastUpdate extends NpmLastUpdateBase {
|
||||
abbreviated: true,
|
||||
})
|
||||
|
||||
const date = dayjs(packageData.modified)
|
||||
|
||||
if (!date.isValid) {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid date' })
|
||||
}
|
||||
|
||||
return this.constructor.render({ date })
|
||||
return renderDateBadge(packageData.modified)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { pathParams } from '../index.js'
|
||||
import { age } from '../color-formatters.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { OpenVSXBase, description } from './open-vsx-base.js'
|
||||
|
||||
export default class OpenVSXReleaseDate extends OpenVSXBase {
|
||||
@ -32,17 +31,8 @@ export default class OpenVSXReleaseDate extends OpenVSXBase {
|
||||
|
||||
static defaultBadgeData = { label: 'release date' }
|
||||
|
||||
static render({ releaseDate }) {
|
||||
return {
|
||||
message: formatDate(releaseDate),
|
||||
color: age(releaseDate),
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ namespace, extension }) {
|
||||
const { timestamp } = await this.fetch({ namespace, extension })
|
||||
return this.constructor.render({
|
||||
releaseDate: timestamp,
|
||||
})
|
||||
return renderDateBadge(timestamp)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import dayjs from 'dayjs'
|
||||
import { pathParams, queryParam, NotFound, InvalidResponse } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { pathParams, queryParam, NotFound } from '../index.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import SnapcraftBase, { snapcraftPackageParam } from './snapcraft-base.js'
|
||||
|
||||
const queryParamSchema = Joi.object({
|
||||
@ -57,13 +55,6 @@ export default class SnapcraftLastUpdate extends SnapcraftBase {
|
||||
},
|
||||
}
|
||||
|
||||
static render({ lastUpdatedDate }) {
|
||||
return {
|
||||
message: formatDate(lastUpdatedDate),
|
||||
color: ageColor(lastUpdatedDate),
|
||||
}
|
||||
}
|
||||
|
||||
static transform(apiData, track, risk, arch) {
|
||||
const channelMap = apiData['channel-map']
|
||||
let filteredChannelMap = channelMap.filter(
|
||||
@ -99,12 +90,6 @@ export default class SnapcraftLastUpdate extends SnapcraftBase {
|
||||
arch,
|
||||
)
|
||||
|
||||
const lastUpdatedDate = dayjs(channel['released-at'])
|
||||
|
||||
if (!lastUpdatedDate.isValid) {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid date' })
|
||||
}
|
||||
|
||||
return this.constructor.render({ lastUpdatedDate })
|
||||
return renderDateBadge(channel['released-at'])
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Joi from 'joi'
|
||||
import { BaseJsonService, pathParams } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
|
||||
const schema = Joi.object({
|
||||
commits: Joi.array()
|
||||
@ -35,13 +34,6 @@ export default class SourceforgeLastCommit extends BaseJsonService {
|
||||
|
||||
static defaultBadgeData = { label: 'last commit' }
|
||||
|
||||
static render({ commitDate }) {
|
||||
return {
|
||||
message: formatDate(new Date(commitDate)),
|
||||
color: ageColor(new Date(commitDate)),
|
||||
}
|
||||
}
|
||||
|
||||
async fetch({ project }) {
|
||||
return this._requestJson({
|
||||
url: `https://sourceforge.net/rest/p/${project}/git/commits`,
|
||||
@ -54,8 +46,6 @@ export default class SourceforgeLastCommit extends BaseJsonService {
|
||||
|
||||
async handle({ project }) {
|
||||
const body = await this.fetch({ project })
|
||||
return this.constructor.render({
|
||||
commitDate: body.commits[0].committed_date,
|
||||
})
|
||||
return renderDateBadge(body.commits[0].committed_date)
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import Joi from 'joi'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { renderDownloadsBadge } from '../downloads.js'
|
||||
import { metric, formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { metric } from '../text-formatters.js'
|
||||
import { NotFound, pathParams } from '../index.js'
|
||||
import BaseSteamAPI from './steam-base.js'
|
||||
|
||||
@ -242,13 +242,9 @@ class SteamFileReleaseDate extends SteamFileService {
|
||||
label: 'release date',
|
||||
}
|
||||
|
||||
static render({ releaseDate }) {
|
||||
return { message: formatDate(releaseDate), color: ageColor(releaseDate) }
|
||||
}
|
||||
|
||||
async onRequest({ response }) {
|
||||
const releaseDate = new Date(0).setUTCSeconds(response.time_created)
|
||||
return this.constructor.render({ releaseDate })
|
||||
return renderDateBadge(releaseDate)
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,13 +273,9 @@ class SteamFileUpdateDate extends SteamFileService {
|
||||
label: 'update date',
|
||||
}
|
||||
|
||||
static render({ updateDate }) {
|
||||
return { message: formatDate(updateDate), color: ageColor(updateDate) }
|
||||
}
|
||||
|
||||
async onRequest({ response }) {
|
||||
const updateDate = new Date(0).setUTCSeconds(response.time_updated)
|
||||
return this.constructor.render({ updateDate })
|
||||
return renderDateBadge(updateDate)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,6 @@
|
||||
* @module
|
||||
*/
|
||||
|
||||
import dayjs from 'dayjs'
|
||||
import calendar from 'dayjs/plugin/calendar.js'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime.js'
|
||||
dayjs.extend(calendar)
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
/**
|
||||
* Creates a string of stars and empty stars based on the rating.
|
||||
* The number of stars is determined by the integer part of the rating.
|
||||
@ -165,39 +159,6 @@ function maybePluralize(singular, countable, plural) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted date string without the year based on the value of input date param d.
|
||||
*
|
||||
* @param {Date | string | number | object } d - Input date in dayjs compatible format, date object, datestring, Unix timestamp etc.
|
||||
* @returns {string} Formatted date string
|
||||
*/
|
||||
function formatDate(d) {
|
||||
const date = dayjs(d)
|
||||
const dateString = date.calendar(null, {
|
||||
lastDay: '[yesterday]',
|
||||
sameDay: '[today]',
|
||||
lastWeek: '[last] dddd',
|
||||
sameElse: 'MMMM YYYY',
|
||||
})
|
||||
// Trim current year from date string
|
||||
return dateString.replace(` ${dayjs().year()}`, '').toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a relative date from the input timestamp.
|
||||
* For example, day after tomorrow's timestamp will return 'in 2 days'.
|
||||
*
|
||||
* @param {number | string} timestamp - Unix timestamp
|
||||
* @returns {string} Relative date from the unix timestamp
|
||||
*/
|
||||
function formatRelativeDate(timestamp) {
|
||||
const parsedDate = dayjs.unix(parseInt(timestamp, 10))
|
||||
if (!parsedDate.isValid()) {
|
||||
return 'invalid date'
|
||||
}
|
||||
return dayjs().to(parsedDate).toLowerCase()
|
||||
}
|
||||
|
||||
export {
|
||||
starRating,
|
||||
currencyFromCode,
|
||||
@ -206,6 +167,4 @@ export {
|
||||
omitv,
|
||||
addv,
|
||||
maybePluralize,
|
||||
formatDate,
|
||||
formatRelativeDate,
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { test, given } from 'sazerac'
|
||||
import sinon from 'sinon'
|
||||
import {
|
||||
starRating,
|
||||
currencyFromCode,
|
||||
@ -8,8 +7,6 @@ import {
|
||||
omitv,
|
||||
addv,
|
||||
maybePluralize,
|
||||
formatDate,
|
||||
formatRelativeDate,
|
||||
} from './text-formatters.js'
|
||||
|
||||
describe('Text formatters', function () {
|
||||
@ -113,54 +110,4 @@ describe('Text formatters', function () {
|
||||
given('box', [123, 456], 'boxes').expect('boxes')
|
||||
given('box', undefined, 'boxes').expect('boxes')
|
||||
})
|
||||
|
||||
test(formatDate, () => {
|
||||
given(1465513200000)
|
||||
.describe('when given a timestamp in june 2016')
|
||||
.expect('june 2016')
|
||||
})
|
||||
|
||||
context('in october', function () {
|
||||
let clock
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(new Date(2017, 9, 15).getTime())
|
||||
})
|
||||
afterEach(function () {
|
||||
clock.restore()
|
||||
})
|
||||
|
||||
test(formatDate, () => {
|
||||
given(new Date(2017, 0, 1).getTime())
|
||||
.describe('when given the beginning of this year')
|
||||
.expect('january')
|
||||
})
|
||||
})
|
||||
|
||||
context('in october', function () {
|
||||
let clock
|
||||
beforeEach(function () {
|
||||
clock = sinon.useFakeTimers(new Date(2018, 9, 29).getTime())
|
||||
})
|
||||
afterEach(function () {
|
||||
clock.restore()
|
||||
})
|
||||
|
||||
test(formatRelativeDate, () => {
|
||||
given(new Date(2018, 9, 31).getTime() / 1000)
|
||||
.describe('when given the end of october')
|
||||
.expect('in 2 days')
|
||||
})
|
||||
|
||||
test(formatRelativeDate, () => {
|
||||
given(new Date(2018, 9, 1).getTime() / 1000)
|
||||
.describe('when given the beginning of october')
|
||||
.expect('a month ago')
|
||||
})
|
||||
|
||||
test(formatRelativeDate, () => {
|
||||
given(9999999999999)
|
||||
.describe('when given invalid date')
|
||||
.expect('invalid date')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { pathParams } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import { BaseVaadinDirectoryService } from './vaadin-directory-base.js'
|
||||
|
||||
export default class VaadinDirectoryReleaseDate extends BaseVaadinDirectoryService {
|
||||
@ -27,14 +26,8 @@ export default class VaadinDirectoryReleaseDate extends BaseVaadinDirectoryServi
|
||||
label: 'latest release date',
|
||||
}
|
||||
|
||||
static render({ date }) {
|
||||
return { message: formatDate(date), color: ageColor(date) }
|
||||
}
|
||||
|
||||
async handle({ alias, packageName }) {
|
||||
const data = await this.fetch({ packageName })
|
||||
return this.constructor.render({
|
||||
date: data.latestAvailableRelease.publicationDate,
|
||||
})
|
||||
return renderDateBadge(data.latestAvailableRelease.publicationDate)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { pathParams } from '../index.js'
|
||||
import { age } from '../color-formatters.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import VisualStudioMarketplaceBase from './visual-studio-marketplace-base.js'
|
||||
|
||||
export default class VisualStudioMarketplaceLastUpdated extends VisualStudioMarketplaceBase {
|
||||
@ -28,13 +27,6 @@ export default class VisualStudioMarketplaceLastUpdated extends VisualStudioMark
|
||||
label: 'last updated',
|
||||
}
|
||||
|
||||
static render({ lastUpdated }) {
|
||||
return {
|
||||
message: formatDate(lastUpdated),
|
||||
color: age(lastUpdated),
|
||||
}
|
||||
}
|
||||
|
||||
transform({ json }) {
|
||||
const { extension } = this.transformExtension({ json })
|
||||
const lastUpdated = extension.lastUpdated
|
||||
@ -44,6 +36,6 @@ export default class VisualStudioMarketplaceLastUpdated extends VisualStudioMark
|
||||
async handle({ extensionId }) {
|
||||
const json = await this.fetch({ extensionId })
|
||||
const { lastUpdated } = this.transform({ json })
|
||||
return this.constructor.render({ lastUpdated })
|
||||
return renderDateBadge(lastUpdated)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { pathParams } from '../index.js'
|
||||
import { age } from '../color-formatters.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { renderDateBadge } from '../date.js'
|
||||
import VisualStudioMarketplaceBase from './visual-studio-marketplace-base.js'
|
||||
|
||||
export default class VisualStudioMarketplaceReleaseDate extends VisualStudioMarketplaceBase {
|
||||
@ -28,13 +27,6 @@ export default class VisualStudioMarketplaceReleaseDate extends VisualStudioMark
|
||||
label: 'release date',
|
||||
}
|
||||
|
||||
static render({ releaseDate }) {
|
||||
return {
|
||||
message: formatDate(releaseDate),
|
||||
color: age(releaseDate),
|
||||
}
|
||||
}
|
||||
|
||||
transform({ json }) {
|
||||
const { extension } = this.transformExtension({ json })
|
||||
const releaseDate = extension.releaseDate
|
||||
@ -44,6 +36,6 @@ export default class VisualStudioMarketplaceReleaseDate extends VisualStudioMark
|
||||
async handle({ extensionId }) {
|
||||
const json = await this.fetch({ extensionId })
|
||||
const { releaseDate } = this.transform({ json })
|
||||
return this.constructor.render({ releaseDate })
|
||||
return renderDateBadge(releaseDate)
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,12 @@
|
||||
import dayjs from 'dayjs'
|
||||
import customParseFormat from 'dayjs/plugin/customParseFormat.js'
|
||||
import { InvalidResponse, pathParams } from '../index.js'
|
||||
import { formatDate } from '../text-formatters.js'
|
||||
import { age as ageColor } from '../color-formatters.js'
|
||||
import { pathParams } from '../index.js'
|
||||
import { parseDate, renderDateBadge } from '../date.js'
|
||||
import { description, BaseWordpress } from './wordpress-base.js'
|
||||
dayjs.extend(customParseFormat)
|
||||
|
||||
const extensionData = {
|
||||
plugin: {
|
||||
capt: 'Plugin',
|
||||
exampleSlug: 'bbpress',
|
||||
lastUpdateFormat: 'YYYY-MM-DD hh:mma [GMT]',
|
||||
lastUpdateFormat: 'YYYY-MM-DD h:mma [GMT]',
|
||||
},
|
||||
theme: {
|
||||
capt: 'Theme',
|
||||
@ -50,35 +46,15 @@ function LastUpdateForType(extensionType) {
|
||||
|
||||
static defaultBadgeData = { label: 'last updated' }
|
||||
|
||||
static render({ lastUpdated }) {
|
||||
return {
|
||||
label: 'last updated',
|
||||
message: formatDate(lastUpdated),
|
||||
color: ageColor(lastUpdated),
|
||||
}
|
||||
}
|
||||
|
||||
transform(lastUpdate) {
|
||||
const date = dayjs(lastUpdate, lastUpdateFormat)
|
||||
|
||||
if (date.isValid()) {
|
||||
return date.format('YYYY-MM-DD')
|
||||
} else {
|
||||
throw new InvalidResponse({ prettyMessage: 'invalid date' })
|
||||
}
|
||||
}
|
||||
|
||||
async handle({ slug }) {
|
||||
const { last_updated: lastUpdated } = await this.fetch({
|
||||
extensionType,
|
||||
slug,
|
||||
})
|
||||
|
||||
const newDate = this.transform(lastUpdated)
|
||||
const date = parseDate(lastUpdated, lastUpdateFormat)
|
||||
|
||||
return this.constructor.render({
|
||||
lastUpdated: newDate,
|
||||
})
|
||||
return renderDateBadge(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user