From 9a6daf34f9c40081681c4c98ae8f665cb985c3c5 Mon Sep 17 00:00:00 2001 From: David Diaz Date: Sun, 22 Nov 2020 15:00:25 -0600 Subject: [PATCH] Config is passing tests. --- package-lock.json | 91 +++++++++ package.json | 8 +- src/__mocks__/shared.js | 4 - src/__mocks__/shared.ts | 1 + .../__snapshots__/config.spec.js.snap | 182 ------------------ .../__snapshots__/config.spec.ts.snap | 166 ++++++++++++++++ .../{config.spec.js => config.spec.ts} | 46 +++-- src/{beau.js => beau.ts} | 13 +- src/config.js | 100 ---------- src/config.ts | 120 ++++++++++++ src/{plugins.js => plugins.ts} | 3 +- src/{shared.js => shared.ts} | 46 ++--- tsconfig.json | 13 ++ 13 files changed, 450 insertions(+), 343 deletions(-) delete mode 100644 src/__mocks__/shared.js create mode 100644 src/__mocks__/shared.ts delete mode 100644 src/__tests__/__snapshots__/config.spec.js.snap create mode 100644 src/__tests__/__snapshots__/config.spec.ts.snap rename src/__tests__/{config.spec.js => config.spec.ts} (77%) rename src/{beau.js => beau.ts} (58%) delete mode 100644 src/config.js create mode 100644 src/config.ts rename src/{plugins.js => plugins.ts} (98%) rename src/{shared.js => shared.ts} (60%) create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index 5d4099e..64b14d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1555,6 +1555,15 @@ "@types/responselike": "*" } }, + "@types/deepmerge": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/deepmerge/-/deepmerge-2.2.0.tgz", + "integrity": "sha512-FEQYDHh6+Q+QXKSrIY46m+/lAmAj/bk4KpLaam+hArmzaVpMBHLcfwOH2Q2UOkWM7XsdY9PmZpGyPAjh/JRGhQ==", + "dev": true, + "requires": { + "deepmerge": "*" + } + }, "@types/graceful-fs": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", @@ -1594,6 +1603,22 @@ "@types/istanbul-lib-report": "*" } }, + "@types/jest": { + "version": "26.0.15", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.15.tgz", + "integrity": "sha512-s2VMReFXRg9XXxV+CW9e5Nz8fH2K1aEhwgjUqPPbQd7g95T0laAcvLv032EhFHIa5GHsZ8W7iJEQVaJq6k3Gog==", + "dev": true, + "requires": { + "jest-diff": "^26.0.0", + "pretty-format": "^26.0.0" + } + }, + "@types/js-yaml": { + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.5.tgz", + "integrity": "sha512-JCcp6J0GV66Y4ZMDAQCXot4xprYB+Zfd3meK9+INSJeVZwJmHAW30BBEEkPzXswMXuiyReUGOP3GxrADc9wPww==", + "dev": true + }, "@types/keyv": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", @@ -2242,6 +2267,15 @@ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", "dev": true }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, "bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -6739,6 +6773,12 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -6941,6 +6981,12 @@ } } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", @@ -7319,6 +7365,12 @@ } } }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -9694,6 +9746,39 @@ "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", "dev": true }, + "ts-jest": { + "version": "26.4.4", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.4.4.tgz", + "integrity": "sha512-3lFWKbLxJm34QxyVNNCgXX1u4o/RV0myvA2y2Bxm46iGIjKlaY0own9gIckbjZJPn+WaJEnfPPJ20HHGpoq4yg==", + "dev": true, + "requires": { + "@types/jest": "26.x", + "bs-logger": "0.x", + "buffer-from": "1.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^26.1.0", + "json5": "2.x", + "lodash.memoize": "4.x", + "make-error": "1.x", + "mkdirp": "1.x", + "semver": "7.x", + "yargs-parser": "20.x" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + } + } + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -9747,6 +9832,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz", + "integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==", + "dev": true + }, "union-value": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", diff --git a/package.json b/package.json index a4d22dd..1123703 100644 --- a/package.json +++ b/package.json @@ -37,10 +37,15 @@ }, "repository": "git@github.com:Seich/Beau.git", "devDependencies": { + "@types/deepmerge": "2.2.0", + "@types/jest": "26.0.15", + "@types/js-yaml": "3.12.5", "jest": "26.6.3", "jest-watch-typeahead": "0.6.1", + "np": "7.0.0", "strip-ansi": "6.0.0", - "np": "7.0.0" + "ts-jest": "26.4.4", + "typescript": "4.1.2" }, "oclif": { "commands": "./bin/cli/commands", @@ -51,6 +56,7 @@ ] }, "jest": { + "preset": "ts-jest", "testEnvironment": "node", "notify": true, "watchPlugins": [ diff --git a/src/__mocks__/shared.js b/src/__mocks__/shared.js deleted file mode 100644 index b16d377..0000000 --- a/src/__mocks__/shared.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - ...jest.requireActual('../shared'), - moduleVersion: jest.fn().mockReturnValue(1) -} diff --git a/src/__mocks__/shared.ts b/src/__mocks__/shared.ts new file mode 100644 index 0000000..0f72137 --- /dev/null +++ b/src/__mocks__/shared.ts @@ -0,0 +1 @@ +export const moduleVersion = jest.fn().mockReturnValue(1) diff --git a/src/__tests__/__snapshots__/config.spec.js.snap b/src/__tests__/__snapshots__/config.spec.js.snap deleted file mode 100644 index d451c22..0000000 --- a/src/__tests__/__snapshots__/config.spec.js.snap +++ /dev/null @@ -1,182 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Config should load multiple hosts 1`] = ` -Config { - "COOKIEJAR": false, - "DEFAULTS": Object { - "HEADERS": Object { - "hello": "mars", - }, - }, - "ENDPOINT": "http://example.org", - "ENVIRONMENT": Object {}, - "HOSTS": Array [ - Object { - "GET /e2": "e2", - "GET /posts": "posts", - "defaults": Object { - "HEADERS": Object { - "hello": "world", - "world": "hello", - }, - }, - "endpoint": "http://example.com", - "host": "com", - }, - Object { - "GET /e3": "e3", - "GET /posts": "posts", - "defaults": Object { - "HEADERS": Object { - "hello": "world", - "world": "bye", - }, - }, - "endpoint": "http://example.net", - "host": "net", - }, - Object { - "GET /posts": "posts", - "endpoint": "http://example.info", - "host": "info", - }, - ], - "PLUGINS": Plugins { - "autoload": Array [ - "std", - ], - "context": Object {}, - "registry": Object { - "dynamicValues": Array [], - "postRequestModifiers": Array [], - "preRequestModifiers": Array [], - }, - }, - "REQUESTS": Array [ - Object { - "ALIAS": "e1", - "COOKIEJAR": false, - "ENDPOINT": "http://example.org", - "HEADERS": Object { - "hello": "mars", - }, - "REQUEST": "GET /e1", - }, - Object { - "ALIAS": "com:e2", - "COOKIEJAR": false, - "ENDPOINT": "http://example.com", - "HEADERS": Object { - "hello": "world", - "world": "hello", - }, - "REQUEST": "GET /e2", - }, - Object { - "ALIAS": "com:posts", - "COOKIEJAR": false, - "ENDPOINT": "http://example.com", - "HEADERS": Object { - "hello": "world", - "world": "hello", - }, - "REQUEST": "GET /posts", - }, - Object { - "ALIAS": "net:e3", - "COOKIEJAR": false, - "ENDPOINT": "http://example.net", - "HEADERS": Object { - "hello": "world", - "world": "bye", - }, - "REQUEST": "GET /e3", - }, - Object { - "ALIAS": "net:posts", - "COOKIEJAR": false, - "ENDPOINT": "http://example.net", - "HEADERS": Object { - "hello": "world", - "world": "bye", - }, - "REQUEST": "GET /posts", - }, - Object { - "ALIAS": "info:posts", - "COOKIEJAR": false, - "ENDPOINT": "http://example.info", - "HEADERS": Object { - "hello": "mars", - }, - "REQUEST": "GET /posts", - }, - ], - "VERSION": 1, - "configKeys": Array [ - "VERSION", - "ENDPOINT", - "PLUGINS", - "DEFAULTS", - "ENVIRONMENT", - "HOSTS", - "COOKIEJAR", - ], -} -`; - -exports[`Config should set up defaults for all requests 1`] = ` -Config { - "COOKIEJAR": false, - "DEFAULTS": Object { - "HEADERS": Object { - "authentication": "hello", - }, - }, - "ENDPOINT": "http://example.com", - "ENVIRONMENT": Object {}, - "HOSTS": Array [], - "PLUGINS": Plugins { - "autoload": Array [ - "std", - ], - "context": Object {}, - "registry": Object { - "dynamicValues": Array [], - "postRequestModifiers": Array [], - "preRequestModifiers": Array [], - }, - }, - "REQUESTS": Array [ - Object { - "ALIAS": "get-post", - "COOKIEJAR": false, - "ENDPOINT": "http://example.com", - "HEADERS": Object { - "authentication": "hello", - }, - "REQUEST": "GET /posts/1", - }, - Object { - "ALIAS": "user", - "COOKIEJAR": false, - "ENDPOINT": "http://example.com", - "HEADERS": Object { - "authentication": "hello", - "hello": "world", - }, - "REQUEST": "GET /user", - }, - ], - "VERSION": 1, - "configKeys": Array [ - "VERSION", - "ENDPOINT", - "PLUGINS", - "DEFAULTS", - "ENVIRONMENT", - "HOSTS", - "COOKIEJAR", - ], -} -`; diff --git a/src/__tests__/__snapshots__/config.spec.ts.snap b/src/__tests__/__snapshots__/config.spec.ts.snap new file mode 100644 index 0000000..3cc39f0 --- /dev/null +++ b/src/__tests__/__snapshots__/config.spec.ts.snap @@ -0,0 +1,166 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Config should load multiple hosts 1`] = ` +Config { + "cookiejar": false, + "defaults": Object { + "headers": Object { + "hello": "mars", + }, + }, + "endpoint": "http://example.org", + "environment": Object {}, + "host": undefined, + "hosts": Array [ + Object { + "GET /e2": "e2", + "GET /posts": "posts", + "defaults": Object { + "headers": Object { + "hello": "world", + "world": "hello", + }, + }, + "endpoint": "http://example.com", + "host": "com", + }, + Object { + "GET /e3": "e3", + "GET /posts": "posts", + "defaults": Object { + "headers": Object { + "hello": "world", + "world": "bye", + }, + }, + "endpoint": "http://example.net", + "host": "net", + }, + Object { + "GET /posts": "posts", + "endpoint": "http://example.info", + "host": "info", + }, + ], + "plugins": Plugins { + "autoload": Array [ + "std", + ], + "context": Object {}, + "registry": Object { + "dynamicValues": Array [], + "postRequestModifiers": Array [], + "preRequestModifiers": Array [], + }, + }, + "requests": Array [ + Object { + "alias": "e1", + "cookiejar": false, + "endpoint": "http://example.org", + "headers": Object { + "hello": "mars", + }, + "request": "GET /e1", + }, + Object { + "alias": "com:e2", + "cookiejar": false, + "endpoint": "http://example.com", + "headers": Object { + "hello": "world", + "world": "hello", + }, + "request": "GET /e2", + }, + Object { + "alias": "com:posts", + "cookiejar": false, + "endpoint": "http://example.com", + "headers": Object { + "hello": "world", + "world": "hello", + }, + "request": "GET /posts", + }, + Object { + "alias": "net:e3", + "cookiejar": false, + "endpoint": "http://example.net", + "headers": Object { + "hello": "world", + "world": "bye", + }, + "request": "GET /e3", + }, + Object { + "alias": "net:posts", + "cookiejar": false, + "endpoint": "http://example.net", + "headers": Object { + "hello": "world", + "world": "bye", + }, + "request": "GET /posts", + }, + Object { + "alias": "info:posts", + "cookiejar": false, + "endpoint": "http://example.info", + "headers": Object { + "hello": "mars", + }, + "request": "GET /posts", + }, + ], + "version": 1, +} +`; + +exports[`Config should set up defaults for all requests 1`] = ` +Config { + "cookiejar": false, + "defaults": Object { + "headers": Object { + "authentication": "hello", + }, + }, + "endpoint": "http://example.com", + "environment": Object {}, + "host": undefined, + "hosts": Array [], + "plugins": Plugins { + "autoload": Array [ + "std", + ], + "context": Object {}, + "registry": Object { + "dynamicValues": Array [], + "postRequestModifiers": Array [], + "preRequestModifiers": Array [], + }, + }, + "requests": Array [ + Object { + "alias": "get-post", + "cookiejar": false, + "endpoint": "http://example.com", + "headers": Object { + "authentication": "hello", + }, + "request": "GET /posts/1", + }, + Object { + "alias": "user", + "cookiejar": false, + "endpoint": "http://example.com", + "headers": Object { + "authentication": "hello", + "hello": "world", + }, + "request": "GET /user", + }, + ], + "version": 1, +} +`; diff --git a/src/__tests__/config.spec.js b/src/__tests__/config.spec.ts similarity index 77% rename from src/__tests__/config.spec.js rename to src/__tests__/config.spec.ts index 463cf2d..1930641 100644 --- a/src/__tests__/config.spec.js +++ b/src/__tests__/config.spec.ts @@ -1,25 +1,23 @@ -const yaml = require('js-yaml') -const Config = require('../config') +import Config, { parseBeauConfig } from '../config' const requireg = require('requireg') requireg.resolving = false describe('Config', () => { it('should load valid config keys', () => { - const doc = yaml.safeLoad(` + const doc = parseBeauConfig(` version: 1 endpoint: http://martianwabbit.com shouldntBeAdded: true `) const config = new Config(doc) - expect(config.ENDPOINT).toBe(doc.endpoint) - expect(config.VERSION).toBe(doc.version) - expect(config.shouldntBeAdded).toBeUndefined() + expect(config.endpoint).toBe(doc.endpoint) + expect(config.version).toBe(doc.version) }) it('should load requests', () => { - const doc = yaml.safeLoad(` + const doc = parseBeauConfig(` endpoint: http://example.com GET /profile: get-profile @@ -32,16 +30,16 @@ describe('Config', () => { `) const config = new Config(doc) - expect(Object.keys(config.REQUESTS).length).toBe(4) + expect(Object.keys(config.requests).length).toBe(4) }) it('should set up defaults for all requests', () => { - const doc = yaml.safeLoad(` + const doc = parseBeauConfig(` version: 1 endpoint: 'http://example.com' defaults: - HEADERS: + headers: authentication: hello GET /posts/1: get-post @@ -54,18 +52,18 @@ describe('Config', () => { const config = new Config(doc) expect(config).toMatchSnapshot() - Object.values(config.REQUESTS).forEach((r) => { - expect(r.HEADERS.authentication).toMatch('hello') + Object.values(config.requests).forEach((r: any) => { + expect(r.headers.authentication).toMatch('hello') }) }) it('should load multiple hosts', () => { - const doc = yaml.safeLoad(` + const doc = parseBeauConfig(` version: 1 endpoint: http://example.org defaults: - HEADERS: + headers: hello: mars GET /e1: e1 @@ -75,7 +73,7 @@ describe('Config', () => { endpoint: http://example.com defaults: - HEADERS: + headers: hello: world world: hello @@ -86,7 +84,7 @@ describe('Config', () => { endpoint: http://example.net defaults: - HEADERS: + headers: hello: world world: bye @@ -105,7 +103,7 @@ describe('Config', () => { }) it('should namespace all aliases within an host', () => { - const doc = yaml.safeLoad(` + const doc = parseBeauConfig(` hosts: - host: test1 endpoint: http://example.com @@ -117,12 +115,12 @@ describe('Config', () => { let config = new Config(doc) - expect(config.REQUESTS[0].ALIAS).toBe('test1:posts') - expect(config.REQUESTS[1].ALIAS).toBe('test2:posts') + expect(config.requests[0].alias).toEqual('test1:posts') + expect(config.requests[1].alias).toEqual('test2:posts') }) it(`should throw if host doesn't have a host key`, () => { - const doc = yaml.safeLoad(` + const doc = parseBeauConfig(` hosts: - endpoint: http://example.com GET /posts: posts @@ -136,7 +134,7 @@ describe('Config', () => { }) it(`should merge host settings with global settings`, () => { - const doc = yaml.safeLoad(` + const doc = parseBeauConfig(` defaults: headers: hello: 1 @@ -155,11 +153,11 @@ describe('Config', () => { `) let config = new Config(doc) - expect(config.REQUESTS[0].HEADERS.hello).toBe(1) + expect(config.requests[0].headers.hello).toBe(1) }) it(`should allow different settings for the same request`, () => { - const doc = yaml.safeLoad(` + const doc = parseBeauConfig(` host: https://example.com GET /1: - alias: req1 @@ -171,6 +169,6 @@ describe('Config', () => { `) let config = new Config(doc) - expect(config.REQUESTS.length).toBe(2) + expect(config.requests.length).toBe(2) }) }) diff --git a/src/beau.js b/src/beau.ts similarity index 58% rename from src/beau.js rename to src/beau.ts index 45a5c72..4978b28 100644 --- a/src/beau.js +++ b/src/beau.ts @@ -1,10 +1,15 @@ +import deepmerge from "deepmerge" +import {BeauConfig, Config} from "./config" +import {moduleVersion} from './shared' + const RequestList = require('./requestList') -const Config = require('./config') -const { moduleVersion } = require('./shared') class Beau { - constructor(doc, env = {}) { - this.config = new Config(doc, env) + config: Config + + constructor(doc: BeauConfig, env = {}) { + doc.environment = deepmerge(doc.environment, env) + this.config = new Config(doc) this.requests = new RequestList(this.config) if (this.config.VERSION !== moduleVersion()) { diff --git a/src/config.js b/src/config.js deleted file mode 100644 index 2e7056f..0000000 --- a/src/config.js +++ /dev/null @@ -1,100 +0,0 @@ -const deepMerge = require('deepmerge') -const { requestRegex, UpperCaseKeys, moduleVersion } = require('./shared') -const Plugins = require('./plugins') - -class Config { - constructor(doc, env = {}) { - const defaultConfigValues = { - VERSION: moduleVersion(), - ENDPOINT: '', - PLUGINS: [], - DEFAULTS: {}, - ENVIRONMENT: {}, - HOSTS: [], - COOKIEJAR: false - } - - this.configKeys = Object.keys(defaultConfigValues) - - let config = this.loadConfig(doc) - Object.assign(this, defaultConfigValues, config) - - this.ENVIRONMENT = deepMerge(this.ENVIRONMENT, env) - - this.REQUESTS = [] - - this.loadRequests(doc, { - DEFAULTS: this.DEFAULTS, - ENDPOINT: this.ENDPOINT - }) - - this.loadHosts(this.HOSTS, config, defaultConfigValues) - - this.PLUGINS = new Plugins(this.PLUGINS) - } - - loadHosts(hosts, rootConfig, defaultConfigValues) { - hosts.forEach((host) => { - if (typeof host.host === 'undefined') { - throw new Error(`Host doesn't indicate it's host name.`) - } - - let config = deepMerge(defaultConfigValues, this.loadConfig(host)) - - config.DEFAULTS = deepMerge(rootConfig.DEFAULTS, config.DEFAULTS) - - this.loadRequests(host, { - DEFAULTS: config.DEFAULTS, - ENDPOINT: config.ENDPOINT, - NAMESPACE: host.host - }) - }) - } - - loadRequests(host, settings) { - Object.entries(host) - .filter(([key]) => requestRegex.test(key)) - .forEach(([key, rDefinition]) => { - if (Array.isArray(rDefinition)) { - rDefinition.forEach((req) => - this.addRequest(key, req, settings) - ) - } else { - this.addRequest(key, rDefinition, settings) - } - }) - } - - addRequest(key, rDefinition, settings) { - let requestDefinitionIsString = typeof rDefinition === 'string' - let originalRequest = requestDefinitionIsString - ? { ALIAS: rDefinition } - : rDefinition - - let request = UpperCaseKeys(originalRequest) - - if (settings.NAMESPACE) { - request.ALIAS = `${settings.NAMESPACE}:${request.ALIAS}` - } - - request.REQUEST = key - request.COOKIEJAR = this.COOKIEJAR - request.ENDPOINT = settings.ENDPOINT - - let defaults = UpperCaseKeys(settings.DEFAULTS) - - this.REQUESTS.push(deepMerge(defaults, request)) - } - - loadConfig(host) { - let config = {} - - Object.entries(host) - .filter(([key]) => this.configKeys.includes(key.toUpperCase())) - .forEach(([key, value]) => (config[key.toUpperCase()] = value)) - - return config - } -} - -module.exports = Config diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..0e1eac6 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,120 @@ +import { requestRegex, moduleVersion } from './shared' +import Plugins from './plugins' +import { safeLoad } from 'js-yaml' + +const deepmerge = require('deepmerge') + +export interface BeauConfig { + cookiejar?: boolean + defaults?: RequestObject + endpoint?: string + environment?: { + [key: string]: UObjectString + } + host?: string + plugins?: UObjectString[] | Plugins + version?: number + hosts?: BeauConfig[] +} + +export interface RequestObject { + endpoint?: string + cookiejar?: boolean + alias?: string + form?: { [key: string]: any } + formdata?: { [key: string]: any } + headers?: { [key: string]: any } + params?: { [key: string]: any } + payload?: UObjectString + request?: string +} + +export type RequestConfig = RequestObject | RequestObject[] | string + +export type UObjectString = { [key: string]: any } | string + +export default class Config implements BeauConfig { + version = moduleVersion() + cookiejar = false + endpoint = '' + + defaults: RequestObject = {} + plugins: Plugins + environment = {} + host?: string = undefined + hosts: BeauConfig[] = [] + + requests: RequestObject[] = [] + + constructor(config: BeauConfig) { + this.version = config.version ?? moduleVersion() + this.cookiejar = config.cookiejar ?? false + this.endpoint = config.endpoint ?? '' + this.defaults = config.defaults ?? {} + this.environment = config.environment ?? {} + this.host = config.host ?? undefined + this.hosts = config.hosts ?? [] + this.plugins = new Plugins() + + if (Array.isArray(config.plugins)) { + this.plugins = new Plugins(config.plugins) + } + + this.loadRequests(config) + this.loadHosts(this.hosts, this) + } + + loadHosts(hosts: BeauConfig[], rootConfig: Config) { + hosts.forEach((host) => { + if (typeof host.host === 'undefined') { + throw new Error(`Host doesn't indicate it's host name.`) + } + + host = deepmerge(rootConfig, host) + host.defaults = deepmerge(rootConfig.defaults, host.defaults) + + this.loadRequests(host) + }) + } + + loadRequests(host: BeauConfig) { + Object.entries(host) + .filter(([key]) => requestRegex.test(key)) + .forEach(([key, rDefinition]: [string, RequestConfig]) => { + if (Array.isArray(rDefinition)) { + rDefinition.forEach((req) => + this.addRequest(key, req, host) + ) + } else { + this.addRequest(key, rDefinition, host) + } + }) + } + + addRequest( + key: string, + request: RequestObject | string, + settings: BeauConfig + ) { + if (typeof request === 'string') { + request = { + alias: request + } + } + + if (settings.host) { + request.alias = `${settings.host}:${request.alias}` + } + + request.request = key + request.cookiejar = this.cookiejar + request.endpoint = settings.endpoint + + this.requests.push(deepmerge(settings.defaults, request)) + } +} + +export function parseBeauConfig(str: string) { + const doc = safeLoad(str) as BeauConfig + return doc +} diff --git a/src/plugins.js b/src/plugins.ts similarity index 98% rename from src/plugins.js rename to src/plugins.ts index 3e2932c..6a047b0 100644 --- a/src/plugins.js +++ b/src/plugins.ts @@ -4,7 +4,7 @@ const deepmerge = require('deepmerge') const { toKebabCase, dynamicValueRegex, replaceInObject } = require('./shared') const { isPlainObject } = require('is-plain-object') -class Plugins { +export default class Plugins { constructor(plugins = [], autoload = ['std']) { this.registry = { preRequestModifiers: [], @@ -116,4 +116,3 @@ class Plugins { } } -module.exports = Plugins diff --git a/src/shared.js b/src/shared.ts similarity index 60% rename from src/shared.js rename to src/shared.ts index e8e96e3..cc8d646 100644 --- a/src/shared.js +++ b/src/shared.ts @@ -1,6 +1,6 @@ -const { URL } = require('url') +import { URL } from 'url' -const httpVerbs = [ +export const httpVerbs = [ 'GET', 'HEAD', 'POST', @@ -12,20 +12,23 @@ const httpVerbs = [ 'PATCH' ] -const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i') -const replacementRegex = /(?:\\?)\$([a-zA-Z\.\d\-\_\:]+)/g -const dynamicValueRegex = /\$\[(\w+\((?:.|[\n\r])*?\))\]/g +export const requestRegex = new RegExp(`(${httpVerbs.join('|')})\\s(.*)`, 'i') +export const replacementRegex = /(?:\\?)\$([a-zA-Z\.\d\-\_\:]+)/g +export const dynamicValueRegex = /\$\[(\w+\((?:.|[\n\r])*?\))\]/g -const UpperCaseKeys = function (obj) { +export const UpperCaseKeys = function (obj: object) { let result = {} Object.entries(obj).forEach(([k, v]) => (result[k.toUpperCase()] = v)) return result } -const isEmptyObject = (obj) => +export const isEmptyObject = (obj: object) => Object.keys(obj).length === 0 && obj.constructor === Object -const removeOptionalKeys = function (obj, optionalValues) { +export const removeOptionalKeys = function ( + obj: object, + optionalValues: string[] +) { let result = {} Object.entries(obj).forEach(([key, value]) => { @@ -39,14 +42,17 @@ const removeOptionalKeys = function (obj, optionalValues) { return result } -const toKebabCase = function (str) { +export const toKebabCase = function (str: string) { return str .trim() .replace(/([a-z])([A-Z])/g, '$1-$2') .toLowerCase() } -const replaceInObject = function (obj, fn) { +export const replaceInObject = function ( + obj: object | string | undefined | null, + fn: (arg0: string) => string +) { if (obj === null) { return null } @@ -66,9 +72,10 @@ const replaceInObject = function (obj, fn) { } } -const moduleVersion = () => parseInt(require('../package.json').version, 10) +export const moduleVersion = () => + parseInt(require('../package.json').version, 10) -const isUrl = function (str) { +export const isUrl = function (str: string) { try { new URL(str) return true @@ -77,23 +84,10 @@ const isUrl = function (str) { } } -const expandPath = (url, path) => { +export const expandPath = (url: string, path: string) => { if (isUrl(path)) { return path } return url.replace(/\/+$/, '') + '/' + path.replace(/^\/+/, '') } - -module.exports = { - requestRegex, - replacementRegex, - dynamicValueRegex, - UpperCaseKeys, - removeOptionalKeys, - toKebabCase, - replaceInObject, - moduleVersion, - isUrl, - expandPath -} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1356852 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "declaration": true, + "importHelpers": true, + "module": "CommonJS", + "outDir": "lib", + "rootDir": "src", + "strict": true, + "target": "ES2017", + "moduleResolution": "Node" + }, + "include": ["src/**/*", "bin/**/*"] +}