diff --git a/.mocharc.json b/.mocharc.json index 2f3a478..0323d17 100644 --- a/.mocharc.json +++ b/.mocharc.json @@ -5,6 +5,6 @@ "ui": "mocha-cakes-2", "exit": true, "require": [ - "./test/helpers/setup.js" + "./test/setup.js" ] } diff --git a/config/test.json b/config/test.json index a9517d8..f9246ea 100644 --- a/config/test.json +++ b/config/test.json @@ -35,5 +35,8 @@ ], "logging": { "pretty": true + }, + "toggle": { + "pafInCommonNamespaces": true } } diff --git a/index.js b/index.js index 6d7e75a..c032f05 100644 --- a/index.js +++ b/index.js @@ -1,19 +1,16 @@ "use strict"; -const namespaces = require("./lib/namespaces"); -const titles = require("./lib/titles"); -const schemas = require("./lib/validation-helpers/schemas"); -const countryCodes = require("./lib/validation-helpers/country-codes"); -const formattingHelpers = require("./lib/validation-helpers/formatting-helpers"); - -const stripSchemaTag = require("./lib/validation-helpers/strip-joi-schema-tags"); - +// helpers const caseBodyHelper = require("./lib/helpers/case-body-helper"); const codeHelper = require("./lib/helpers/code-helper"); +const toggle = require("./lib/helpers/toggle"); + +// utils const email = require("./lib/utils/email"); const ftp = require("./lib/utils/ftp"); const gcpAuth = require("./lib/utils/gcp-auth"); const gcs = require("./lib/utils/gcs"); +const http = require("./lib/utils/http"); const iterators = require("./lib/utils/iterators"); const PDF = require("./lib/utils/pdf"); const pdfGenerator = require("./lib/utils/pdfGenerator"); @@ -21,8 +18,20 @@ const s3 = require("./lib/utils/s3"); const ses = require("./lib/utils/ses"); const sftp = require("./lib/utils/sftp"); const streams = require("./lib/utils/streams"); -const http = require("./lib/utils/http"); +const swedishBankday = require("./lib/utils/swedish-bankday"); +// validation helpers +const countryCodes = require("./lib/validation-helpers/country-codes"); +const formattingHelpers = require("./lib/validation-helpers/formatting-helpers"); +const schemas = require("./lib/validation-helpers/schemas"); +const stripSchemaTag = require("./lib/validation-helpers/strip-schema-tag"); + +// other +const namespaces = require("./lib/namespaces"); +const titles = require("./lib/titles"); + +// test helpers +const clone = require("./test/helpers/clone"); const fakeApi = require("./test/helpers/fake-api"); const fakeFtp = require("./test/helpers/fake-ftp"); const fakeGcpAuth = require("./test/helpers/fake-gcp-auth"); @@ -33,38 +42,44 @@ const fakeSftp = require("./test/helpers/fake-sftp"); const fileUtils = require("./test/helpers/file-utils"); const messageHelper = require("./test/helpers/message-helper"); const pdfReader = require("./test/helpers/pdfReader"); -const clone = require("./test/helpers/clone"); module.exports = { + // helpers caseBodyHelper, codeHelper, - countryCodes, + toggle, + // utils email, - fakeApi, - fakeFtp, - fakeGcpAuth, - fakeGcs, - fakeS3, - fakeSes, - fakeSftp, - fileUtils, - formattingHelpers, ftp, gcpAuth, gcs, http, iterators, - messageHelper, - namespaces, - titles, PDF, pdfGenerator, - pdfReader, - schemas, s3, ses, sftp, streams, + swedishBankday, + // validation helpers + countryCodes, + formattingHelpers, + schemas, stripSchemaTag, + // other + namespaces, + titles, + // test helpers clone, + fakeApi, + fakeFtp, + fakeGcpAuth, + fakeGcs, + fakeS3, + fakeSes, + fakeSftp, + fileUtils, + messageHelper, + pdfReader, }; diff --git a/lib/helpers/toggle.js b/lib/helpers/toggle.js index d1babaf..d8b7026 100644 --- a/lib/helpers/toggle.js +++ b/lib/helpers/toggle.js @@ -1,13 +1,7 @@ "use strict"; -const config = require("exp-config"); +const { toggle: configToggles = {} } = require("exp-config"); -const knownToggles = [ - "pafInCommonNamespaces", -]; - -knownToggles.sort(); - -config.toggle = config.toggle || {}; +const knownToggles = Object.keys(configToggles).sort(); /* c8 ignore start */ function toggle(name) { @@ -18,7 +12,7 @@ function toggle(name) { if (process.env["NODE-DISABLE-TOGGLE"] === name) return false; return true; } - const value = config.toggle[name]; + const value = configToggles[name]; return value === true || value === "true"; } /* c8 ignore stop */ diff --git a/lib/utils/swedish-bankday.js b/lib/utils/swedish-bankday.js new file mode 100644 index 0000000..f5bccb7 --- /dev/null +++ b/lib/utils/swedish-bankday.js @@ -0,0 +1,43 @@ +"use strict"; +const moment = require("moment"); +const { isHoliday } = require("swedish-holidays"); +const bankHolidays = [ + "Nyårsdagen", + "Trettondedag jul", + "Långfredagen", + "Påskafton", + "Påskdagen", + "Annandag påsk", + "Första maj", + "Kristi himmelsfärdsdag", + "Pingstafton", + "Pingstdagen", + "Sveriges nationaldag", + "Midsommarafton", + "Midsommardagen", + "Alla helgons dag", + "Julafton", + "Juldagen", + "Annandag jul", + "Nyårsafton", +]; +function isBankDay(d) { + const md = moment(d); + // weekends are never bankdays + if ([ 0, 6 ].includes(md.weekday())) return false; + const holiday = isHoliday(md.toDate()); + // not a holiday + if (!holiday) return true; + + return !bankHolidays.includes(holiday.name); +} + +function nextBankDay(d) { + let md = moment(d); + do { + md = md.add(1, "day"); + } while (!isBankDay(md)); + return md.format("YYYY-MM-DD"); +} + +module.exports = { isBankDay, nextBankDay }; diff --git a/lib/validation-helpers/strip-joi-schema-tags.js b/lib/validation-helpers/strip-schema-tag.js similarity index 100% rename from lib/validation-helpers/strip-joi-schema-tags.js rename to lib/validation-helpers/strip-schema-tag.js diff --git a/package-lock.json b/package-lock.json index ba80d42..3c3c158 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "lu-common", - "version": "3.8.6", + "version": "3.9.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lu-common", - "version": "3.8.6", + "version": "3.9.1", "license": "UNLICENSED", "dependencies": { "@google-cloud/storage": "^5.18.3", @@ -25,6 +25,7 @@ "pdfkit": "^0.13.0", "sinon": "^15.0.0", "ssh2-sftp-client": "^7.2.3", + "swedish-holidays": "^1.1.2", "urlencode": "^1.1.0" }, "devDependencies": { @@ -2995,9 +2996,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" @@ -5813,6 +5814,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swedish-holidays": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swedish-holidays/-/swedish-holidays-1.1.2.tgz", + "integrity": "sha512-KFcwkKsFnCmuFIZF1MnEhEFWj38hYfmUxJgeqDSNcmP+RoSPFoC0eV3V4fiHWvhtKMBiIICXaO4m5T0/mnq7aQ==" + }, "node_modules/tdigest": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", diff --git a/package.json b/package.json index 5d89025..5090632 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lu-common", - "version": "3.9.0", + "version": "3.9.1", "description": "", "main": "index.js", "engines": { @@ -35,6 +35,7 @@ "pdfkit": "^0.13.0", "sinon": "^15.0.0", "ssh2-sftp-client": "^7.2.3", + "swedish-holidays": "^1.1.2", "urlencode": "^1.1.0" }, "devDependencies": { diff --git a/test-data/unit/validation-helpers/schemas-test-data.js b/test-data/unit/validation-helpers/schemas-test-data.js index 6e6de7b..19ba0a0 100644 --- a/test-data/unit/validation-helpers/schemas-test-data.js +++ b/test-data/unit/validation-helpers/schemas-test-data.js @@ -1,6 +1,6 @@ "use strict"; -const stripSchemaTag = require("../../../lib/validation-helpers/strip-joi-schema-tags"); +const stripSchemaTag = require("../../../lib/validation-helpers/strip-schema-tag"); const { addressSchema } = require("../../../lib/validation-helpers/schemas"); diff --git a/test/feature/index-test.js b/test/feature/index-test.js index a4d5172..1de6245 100644 --- a/test/feature/index-test.js +++ b/test/feature/index-test.js @@ -1,14 +1,21 @@ "use strict"; const common = require("../../index"); -const expect = require("chai").expect; +const fs = require("fs"); +const path = require("path"); + +const paths = [ "lib", "test/helpers" ]; +const allExports = []; +for (const basePath of paths) { + allExports.push(...getPathExports(basePath)); +} const expectedExports = [ + // helpers "caseBodyHelper", "codeHelper", - "namespaces", - "titles", - "schemas", + "toggle", + // utils "email", "ftp", "gcpAuth", @@ -21,6 +28,17 @@ const expectedExports = [ "ses", "sftp", "streams", + "swedishBankday", + // validation helpers + "countryCodes", + "formattingHelpers", + "schemas", + "stripSchemaTag", + // other + "namespaces", + "titles", + // test helpers + "clone", "fakeApi", "fakeFtp", "fakeGcpAuth", @@ -31,25 +49,56 @@ const expectedExports = [ "fileUtils", "messageHelper", "pdfReader", - "stripSchemaTag", - "countryCodes", - "formattingHelpers", - "clone", ]; describe("Exposed features", () => { - const exports = []; - + const exposedExports = []; for (const c in common) { - exports.push(c.toString()); + exposedExports.push(c.toString()); } - describe("Importing default export", () => { - it("The right stuff gets imported", () => { - const list = exports.filter((val) => !expectedExports.includes(val)); - const list2 = expectedExports.filter((val) => !exports.includes(val)); - expect(list.length).to.equal(0); - expect(list2.length).to.equal(0); - }); + describe("everything we expect to export is exposed", () => { + for (const expectedExport of expectedExports) { + it(`${expectedExport} should be exposed`, () => { + exposedExports.should.include(expectedExport); + }); + } + }); + + describe("everything we expose is expected", () => { + for (const exposedExport of exposedExports) { + it(`${exposedExport} is supposed to be exposed`, () => { + expectedExports.should.include(exposedExport); + }); + } + }); + + describe("everything exported by modules is exposed in lu-common", () => { + for (const expectedExport of allExports) { + it(`should export ${expectedExport}`, () => { + exposedExports.should.include(expectedExport); + }); + } }); }); + +function toCamelCase(fileName) { + return fileName.replace(/-([a-z])/g, (g) => g[1].toUpperCase()); +} + +function getPathExports(basePath) { + const exports = []; + const normalizedPath = path.join(__dirname, "..", "..", basePath); + fs.readdirSync(normalizedPath).forEach((file) => { + const filePath = path.join(normalizedPath, file); + const stats = fs.statSync(filePath); + + // get all exports from subdirectories too + if (stats.isDirectory()) exports.push(...getPathExports(path.join(basePath, file))); + else { + const importName = file === "pdf.js" ? "PDF" : toCamelCase(file.replace(".js", "")); + exports.push(importName); + } + }); + return exports; +} diff --git a/test/helpers/setup.js b/test/setup.js similarity index 100% rename from test/helpers/setup.js rename to test/setup.js diff --git a/test/unit/swedish-bankday-test.js b/test/unit/swedish-bankday-test.js new file mode 100644 index 0000000..cd2725e --- /dev/null +++ b/test/unit/swedish-bankday-test.js @@ -0,0 +1,28 @@ +"use strict"; + +const expect = require("chai").expect; + +const swedishBankday = require("../../lib/utils/swedish-bankday"); + +describe("isBankDay", () => { + it("should handle weekdays", () => { + expect(swedishBankday.isBankDay("2020-06-17")).to.eql(true); + expect(swedishBankday.isBankDay("2020-06-21")).to.eql(false); + }); + + it("should handle non-weekend holidays", () => { + expect(swedishBankday.isBankDay("2020-06-19")).to.eql(false); // Midsummer's Day + expect(swedishBankday.isBankDay("2020-04-10")).to.eql(false); // Good Friday + }); +}); + +describe("nextBankDay", () => { + it("should handle weekdays", () => { + expect(swedishBankday.nextBankDay("2020-06-17")).to.eql("2020-06-18"); + }); + + it("should handle non-weekend holidays", () => { + expect(swedishBankday.nextBankDay("2020-06-18")).to.eql("2020-06-22"); // Midsummer's Day + expect(swedishBankday.nextBankDay("2020-04-09")).to.eql("2020-04-14"); // Good Friday + }); +}); diff --git a/test/unit/validation-helpers/strip-joi-schema-tags-test.js b/test/unit/validation-helpers/strip-schema-tag-test.js similarity index 98% rename from test/unit/validation-helpers/strip-joi-schema-tags-test.js rename to test/unit/validation-helpers/strip-schema-tag-test.js index 613ceae..c0fdbeb 100644 --- a/test/unit/validation-helpers/strip-joi-schema-tags-test.js +++ b/test/unit/validation-helpers/strip-schema-tag-test.js @@ -2,7 +2,7 @@ const expect = require("chai").expect; const joi = require("joi"); -const stripper = require("../../../lib/validation-helpers/strip-joi-schema-tags"); +const stripper = require("../../../lib/validation-helpers/strip-schema-tag"); describe("strip joi fields without tags", () => { describe("nested", () => {