mirror of
https://github.com/holidayapi/holidayapi-node.git
synced 2025-06-21 04:26:33 +00:00
feat: get previous workday
This started as a feature request for our upstream API (closes #33) that led to a bit of rework to help make the library a bit more flexible in terms of not needing modification when something on the API changes. This update also includes your typical round of dependency updates and a bit of preemptive planning by way of dropping support for Node.js as we're on the cusp of it being out of maintenance and the release of Node.js v18.
This commit is contained in:
parent
c3de7ff9bd
commit
046aadeea4
7 changed files with 3512 additions and 6265 deletions
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
@ -6,7 +6,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: ['12', '14', '16']
|
node-version: ['14', '16']
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2016, 2017, 2018, 2019, 2020 Gravity Boulevard, LLC
|
Copyright (c) 2016, 2017, 2018, 2019, 2020, 2021, 2022 Gravity Boulevard, LLC
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
9346
package-lock.json
generated
9346
package-lock.json
generated
File diff suppressed because it is too large
Load diff
32
package.json
32
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "holidayapi",
|
"name": "holidayapi",
|
||||||
"version": "5.1.0",
|
"version": "6.0.0",
|
||||||
"description": "Official Node.js library for Holiday API",
|
"description": "Official Node.js library for Holiday API",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
@ -21,26 +21,26 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://holidayapi.com",
|
"homepage": "https://holidayapi.com",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 14.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^26.0.19",
|
"@types/jest": "^27.4.1",
|
||||||
"@types/nock": "^11.1.0",
|
"@types/nock": "^11.1.0",
|
||||||
"@types/node": "^15.12.2",
|
"@types/node": "^17.0.23",
|
||||||
"@types/node-fetch": "^2.5.7",
|
"@types/node-fetch": "^2.6.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.11.1",
|
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||||
"@typescript-eslint/parser": "^4.11.1",
|
"@typescript-eslint/parser": "^5.18.0",
|
||||||
"eslint": "^7.16.0",
|
"eslint": "^8.12.0",
|
||||||
"eslint-config-airbnb-base": "^14.2.1",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
"eslint-plugin-import": "^2.22.1",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-jest": "^24.1.3",
|
"eslint-plugin-jest": "^26.1.3",
|
||||||
"jest": "^27.0.4",
|
"jest": "^27.5.1",
|
||||||
"nock": "^13.0.5",
|
"nock": "^13.2.4",
|
||||||
"ts-jest": "^27.0.3",
|
"ts-jest": "^27.1.4",
|
||||||
"typescript": "^4.1.3"
|
"typescript": "^4.6.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-fetch": "^2.6.1"
|
"node-fetch": "^2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
|
|
@ -56,7 +56,7 @@ export class HolidayAPI {
|
||||||
|
|
||||||
private async request(endpoint: Endpoint, request?: Requests): Promise<Responses> {
|
private async request(endpoint: Endpoint, request?: Requests): Promise<Responses> {
|
||||||
const response = await fetch(this.createUrl(endpoint, request));
|
const response = await fetch(this.createUrl(endpoint, request));
|
||||||
let payload;
|
let payload: any;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
payload = await response.json();
|
payload = await response.json();
|
||||||
|
@ -76,14 +76,6 @@ export class HolidayAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
async holidays(request: HolidaysRequest = {}): Promise<HolidaysResponse> {
|
async holidays(request: HolidaysRequest = {}): Promise<HolidaysResponse> {
|
||||||
if (!request.country) {
|
|
||||||
throw new Error('Missing country');
|
|
||||||
} else if (!request.year) {
|
|
||||||
throw new Error('Missing year');
|
|
||||||
} else if (request.previous && request.upcoming) {
|
|
||||||
throw new Error('Previous and upcoming are mutually exclusive');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.request('holidays', request);
|
return this.request('holidays', request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,28 +84,10 @@ export class HolidayAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
async workday(request: WorkdayRequest = {}): Promise<WorkdayResponse> {
|
async workday(request: WorkdayRequest = {}): Promise<WorkdayResponse> {
|
||||||
if (!request.country) {
|
|
||||||
throw new Error('Missing country');
|
|
||||||
} else if (!request.start) {
|
|
||||||
throw new Error('Missing start date');
|
|
||||||
} else if (!request.days) {
|
|
||||||
throw new Error('Missing days');
|
|
||||||
} else if (request.days < 1) {
|
|
||||||
throw new Error('Days must be 1 or more');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.request('workday', request);
|
return this.request('workday', request);
|
||||||
}
|
}
|
||||||
|
|
||||||
async workdays(request: WorkdaysRequest = {}): Promise<WorkdaysResponse> {
|
async workdays(request: WorkdaysRequest = {}): Promise<WorkdaysResponse> {
|
||||||
if (!request.country) {
|
|
||||||
throw new Error('Missing country');
|
|
||||||
} else if (!request.start) {
|
|
||||||
throw new Error('Missing start date');
|
|
||||||
} else if (!request.end) {
|
|
||||||
throw new Error('Missing end date');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.request('workdays', request);
|
return this.request('workdays', request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,129 +93,6 @@ describe('holidayapi', () => {
|
||||||
expect(await holidayapi.countries()).toStrictEqual(expectedResponse);
|
expect(await holidayapi.countries()).toStrictEqual(expectedResponse);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return only countries with public holidays', async () => {
|
|
||||||
const expectedResponse = {
|
|
||||||
status: 200,
|
|
||||||
requests: {
|
|
||||||
used: 1000,
|
|
||||||
available: 9000,
|
|
||||||
resets: '2019-10-01 00:00:00',
|
|
||||||
},
|
|
||||||
countries: [
|
|
||||||
{
|
|
||||||
code: 'ST',
|
|
||||||
name: 'Sao Tome and Principe',
|
|
||||||
languages: ['pt'],
|
|
||||||
codes: {
|
|
||||||
'alpha-2': 'ST',
|
|
||||||
'alpha-3': 'STP',
|
|
||||||
numeric: 678,
|
|
||||||
},
|
|
||||||
flag: 'https://www.countryflags.io/ST/flat/64.png',
|
|
||||||
subdivisions: [
|
|
||||||
{
|
|
||||||
code: 'ST-P',
|
|
||||||
name: 'Príncipe',
|
|
||||||
languages: ['pt'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'ST-S',
|
|
||||||
name: 'São Tomé',
|
|
||||||
languages: ['pt'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
mockRequest.get(`${basePath}&public=true`).reply(200, expectedResponse);
|
|
||||||
expect(await holidayapi.countries({
|
|
||||||
public: true,
|
|
||||||
})).toStrictEqual(expectedResponse);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return one country', async () => {
|
|
||||||
const expectedResponse = {
|
|
||||||
status: 200,
|
|
||||||
requests: {
|
|
||||||
used: 1000,
|
|
||||||
available: 9000,
|
|
||||||
resets: '2019-10-01 00:00:00',
|
|
||||||
},
|
|
||||||
countries: [
|
|
||||||
{
|
|
||||||
code: 'ST',
|
|
||||||
name: 'Sao Tome and Principe',
|
|
||||||
languages: ['pt'],
|
|
||||||
codes: {
|
|
||||||
'alpha-2': 'ST',
|
|
||||||
'alpha-3': 'STP',
|
|
||||||
numeric: 678,
|
|
||||||
},
|
|
||||||
flag: 'https://www.countryflags.io/ST/flat/64.png',
|
|
||||||
subdivisions: [
|
|
||||||
{
|
|
||||||
code: 'ST-P',
|
|
||||||
name: 'Príncipe',
|
|
||||||
languages: ['pt'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'ST-S',
|
|
||||||
name: 'São Tomé',
|
|
||||||
languages: ['pt'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
mockRequest.get(`${basePath}&country=ST`).reply(200, expectedResponse);
|
|
||||||
expect(await holidayapi.countries({
|
|
||||||
country: 'ST',
|
|
||||||
})).toStrictEqual(expectedResponse);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should search countries', async () => {
|
|
||||||
const expectedResponse = {
|
|
||||||
status: 200,
|
|
||||||
requests: {
|
|
||||||
used: 1000,
|
|
||||||
available: 9000,
|
|
||||||
resets: '2019-10-01 00:00:00',
|
|
||||||
},
|
|
||||||
countries: [
|
|
||||||
{
|
|
||||||
code: 'ST',
|
|
||||||
name: 'Sao Tome and Principe',
|
|
||||||
languages: ['pt'],
|
|
||||||
codes: {
|
|
||||||
'alpha-2': 'ST',
|
|
||||||
'alpha-3': 'STP',
|
|
||||||
numeric: 678,
|
|
||||||
},
|
|
||||||
flag: 'https://www.countryflags.io/ST/flat/64.png',
|
|
||||||
subdivisions: [
|
|
||||||
{
|
|
||||||
code: 'ST-P',
|
|
||||||
name: 'Príncipe',
|
|
||||||
languages: ['pt'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'ST-S',
|
|
||||||
name: 'São Tomé',
|
|
||||||
languages: ['pt'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
mockRequest.get(`${basePath}&search=Sao`).reply(200, expectedResponse);
|
|
||||||
expect(await holidayapi.countries({
|
|
||||||
search: 'Sao',
|
|
||||||
})).toStrictEqual(expectedResponse);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should raise 4xx errors', async () => {
|
it('should raise 4xx errors', async () => {
|
||||||
const expectedResponse = {
|
const expectedResponse = {
|
||||||
status: 429,
|
status: 429,
|
||||||
|
@ -288,81 +165,6 @@ describe('holidayapi', () => {
|
||||||
})).toStrictEqual(expectedResponse);
|
})).toStrictEqual(expectedResponse);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search holidays', async () => {
|
|
||||||
const expectedResponse = {
|
|
||||||
status: 200,
|
|
||||||
requests: {
|
|
||||||
used: 1000,
|
|
||||||
available: 9000,
|
|
||||||
resets: '2019-10-01 00:00:00',
|
|
||||||
},
|
|
||||||
holidays: [
|
|
||||||
{
|
|
||||||
name: 'Independence Day',
|
|
||||||
date: '2015-07-04',
|
|
||||||
observed: '2015-07-03',
|
|
||||||
public: true,
|
|
||||||
country: 'US',
|
|
||||||
uuid: '88268759-9b90-468c-804f-b729b8418e7c',
|
|
||||||
weekday: {
|
|
||||||
date: {
|
|
||||||
name: 'Saturday',
|
|
||||||
numeric: '6',
|
|
||||||
},
|
|
||||||
observed: {
|
|
||||||
name: 'Friday',
|
|
||||||
numeric: '5',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
mockRequest.get(`${basePath}&country=US&year=2019&search=Independence`)
|
|
||||||
.reply(200, expectedResponse);
|
|
||||||
|
|
||||||
expect(await holidayapi.holidays({
|
|
||||||
country: 'US',
|
|
||||||
year: 2019,
|
|
||||||
search: 'Independence',
|
|
||||||
})).toStrictEqual(expectedResponse);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should error when country is missing', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.holidays();
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/missing country/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should error when year is missing', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.holidays({ country: 'US' });
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/missing year/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should error when both previous and upcoming', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.holidays({
|
|
||||||
country: 'US',
|
|
||||||
year: 2019,
|
|
||||||
previous: true,
|
|
||||||
upcoming: true,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/previous and upcoming/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should raise 4xx errors', async () => {
|
it('should raise 4xx errors', async () => {
|
||||||
const expectedResponse = {
|
const expectedResponse = {
|
||||||
status: 429,
|
status: 429,
|
||||||
|
@ -431,54 +233,6 @@ describe('holidayapi', () => {
|
||||||
expect(await holidayapi.languages()).toStrictEqual(expectedResponse);
|
expect(await holidayapi.languages()).toStrictEqual(expectedResponse);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return one language', async () => {
|
|
||||||
const expectedResponse = {
|
|
||||||
status: 200,
|
|
||||||
requests: {
|
|
||||||
used: 1000,
|
|
||||||
available: 9000,
|
|
||||||
resets: '2019-10-01 00:00:00',
|
|
||||||
},
|
|
||||||
languages: [
|
|
||||||
{
|
|
||||||
code: 'hi',
|
|
||||||
name: 'Hindi',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
mockRequest.get(`${basePath}&language=hi`).reply(200, expectedResponse);
|
|
||||||
expect(await holidayapi.languages({
|
|
||||||
language: 'hi',
|
|
||||||
})).toStrictEqual(expectedResponse);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should search languages', async () => {
|
|
||||||
const expectedResponse = {
|
|
||||||
status: 200,
|
|
||||||
requests: {
|
|
||||||
used: 1000,
|
|
||||||
available: 9000,
|
|
||||||
resets: '2019-10-01 00:00:00',
|
|
||||||
},
|
|
||||||
languages: [
|
|
||||||
{
|
|
||||||
code: 'hi',
|
|
||||||
name: 'Hindi',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: 'zh',
|
|
||||||
name: 'Chinese (Simplified)',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
mockRequest.get(`${basePath}&search=in`).reply(200, expectedResponse);
|
|
||||||
expect(await holidayapi.languages({
|
|
||||||
search: 'in',
|
|
||||||
})).toStrictEqual(expectedResponse);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should raise 4xx errors', async () => {
|
it('should raise 4xx errors', async () => {
|
||||||
const expectedResponse = {
|
const expectedResponse = {
|
||||||
status: 429,
|
status: 429,
|
||||||
|
@ -539,46 +293,6 @@ describe('holidayapi', () => {
|
||||||
})).toStrictEqual(expectedResponse);
|
})).toStrictEqual(expectedResponse);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should error when country is missing', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.workday();
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/missing country/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should error when start is missing', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.workday({ country: 'US' });
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/missing start date/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should error when days is missing', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.workday({ country: 'US', start: '2019-07-01' });
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/missing days/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should error when days is negative', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.workday({ country: 'US', start: '2019-07-01', days: -10 });
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/days must be 1 or more/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should raise 4xx errors', async () => {
|
it('should raise 4xx errors', async () => {
|
||||||
const expectedResponse = {
|
const expectedResponse = {
|
||||||
status: 429,
|
status: 429,
|
||||||
|
@ -632,36 +346,6 @@ describe('holidayapi', () => {
|
||||||
})).toStrictEqual(expectedResponse);
|
})).toStrictEqual(expectedResponse);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should error when country is missing', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.workdays();
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/missing country/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should error when start is missing', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.workdays({ country: 'US' });
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/missing start date/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should error when end is missing', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await holidayapi.workdays({ country: 'US', start: '2019-07-01' });
|
|
||||||
} catch (err) {
|
|
||||||
expect(err.message).toMatch(/missing end date/i);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should raise 4xx errors', async () => {
|
it('should raise 4xx errors', async () => {
|
||||||
const expectedResponse = {
|
const expectedResponse = {
|
||||||
status: 429,
|
status: 429,
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true
|
"noUnusedParameters": true,
|
||||||
|
"useUnknownInCatchVariables": false
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*"
|
"src/**/*"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue