From a2a2a7c7be7456ba977d78bab3ccc07330dca378 Mon Sep 17 00:00:00 2001 From: Naz Date: Thu, 30 Sep 2021 19:22:09 +0200 Subject: [PATCH] Added settings-path-manager module refs https://linear.app/tryghost/issue/CORE-35/refactor-route-and-redirect-settings - The module is a tiny path resolver for settings used in Ghost. A first obvious place it's used is for routes.yaml settings files. With a little bit of tweaking it should also be adopted by redirects services --- ghost/settings-path-manager/.eslintrc.js | 6 ++ ghost/settings-path-manager/LICENSE | 21 +++++++ ghost/settings-path-manager/README.md | 53 +++++++++++++++++ ghost/settings-path-manager/index.js | 1 + .../lib/settings-path-manager.js | 40 +++++++++++++ ghost/settings-path-manager/package.json | 30 ++++++++++ ghost/settings-path-manager/test/.eslintrc.js | 6 ++ .../test/settings-path-manager.test.js | 57 +++++++++++++++++++ .../test/utils/assertions.js | 11 ++++ .../settings-path-manager/test/utils/index.js | 11 ++++ .../test/utils/overrides.js | 10 ++++ 11 files changed, 246 insertions(+) create mode 100644 ghost/settings-path-manager/.eslintrc.js create mode 100644 ghost/settings-path-manager/LICENSE create mode 100644 ghost/settings-path-manager/README.md create mode 100644 ghost/settings-path-manager/index.js create mode 100644 ghost/settings-path-manager/lib/settings-path-manager.js create mode 100644 ghost/settings-path-manager/package.json create mode 100644 ghost/settings-path-manager/test/.eslintrc.js create mode 100644 ghost/settings-path-manager/test/settings-path-manager.test.js create mode 100644 ghost/settings-path-manager/test/utils/assertions.js create mode 100644 ghost/settings-path-manager/test/utils/index.js create mode 100644 ghost/settings-path-manager/test/utils/overrides.js diff --git a/ghost/settings-path-manager/.eslintrc.js b/ghost/settings-path-manager/.eslintrc.js new file mode 100644 index 0000000000..c9c1bcb522 --- /dev/null +++ b/ghost/settings-path-manager/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: ['ghost'], + extends: [ + 'plugin:ghost/node' + ] +}; diff --git a/ghost/settings-path-manager/LICENSE b/ghost/settings-path-manager/LICENSE new file mode 100644 index 0000000000..366ae5f624 --- /dev/null +++ b/ghost/settings-path-manager/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2013-2021 Ghost Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ghost/settings-path-manager/README.md b/ghost/settings-path-manager/README.md new file mode 100644 index 0000000000..6ab0f9bf55 --- /dev/null +++ b/ghost/settings-path-manager/README.md @@ -0,0 +1,53 @@ +# Settings Path Manager +A library which helps locating configuration paths in Ghost. For example configs for dynamic routes or redirects. + +## Install + +`npm install @tryghost/settings-path-manager --save` + +or + +`yarn add @tryghost/settings-path-manager` + + +## Usage +Example use in to create routes.yaml configuration files: +```js +const config = require('../shared/config'); // or whatever place the storage folders are configured at + +const settingsPathManager = new SettingsPathManager({ + type: 'routes', + paths: [config.getContentPath('settings')] +}); + +const filePath = settingsPathManager.getDefaultFilePath(); + +console.log(config.getContentPath('settings')); // -> '/content/data/' +console.log(filePath); // -> '/content/data/routes.yaml' +``` + +## Develop + +This is a mono repository, managed with [lerna](https://lernajs.io/). + +Follow the instructions for the top-level repo. +1. `git clone` this repo & `cd` into it as usual +2. Run `yarn` to install top-level dependencies. + + +## Run + +- `yarn dev` + + +## Test + +- `yarn lint` run just eslint +- `yarn test` run lint and tests + + + + +# Copyright & License + +Copyright (c) 2013-2021 Ghost Foundation - Released under the [MIT license](LICENSE). diff --git a/ghost/settings-path-manager/index.js b/ghost/settings-path-manager/index.js new file mode 100644 index 0000000000..a2b42f55db --- /dev/null +++ b/ghost/settings-path-manager/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/settings-path-manager'); diff --git a/ghost/settings-path-manager/lib/settings-path-manager.js b/ghost/settings-path-manager/lib/settings-path-manager.js new file mode 100644 index 0000000000..9064c735f0 --- /dev/null +++ b/ghost/settings-path-manager/lib/settings-path-manager.js @@ -0,0 +1,40 @@ +const path = require('path'); +const tpl = require('@tryghost/tpl'); +const {IncorrectUsageError} = require('@tryghost/errors'); + +const messages = { + incorrectPathsParameter: 'Attempted to setup settings path manager without paths values.' +}; + +class SettingsPathManager { + /** + * + * @param {Object} options + * @param {String[]} options.paths - file location paths ordered in priority by where to locate them first + * @param {String} options.type setting file type, e.g: 'routes' or 'redirects' + * @param {String[]} [options.extensions] the supported file extensions with 'yaml' and 'json' defaults. Note 'yml' extension is ignored on purpose + */ + constructor({type, paths, extensions = ['yaml', 'json']}) { + if (!paths || !paths.length) { + throw new IncorrectUsageError({ + message: tpl(messages.incorrectPathsParameter) + }); + } + + this.type = type; + this.filename = type; + + this.paths = paths; + this.defaultPath = paths[0]; + + this.extensions = extensions; + this.defaultExtension = extensions[0]; + } + + getDefaultFilePath() { + const settingsFolder = this.defaultPath; + return path.join(settingsFolder, `${this.filename}.${this.defaultExtension}`); + } +} + +module.exports = SettingsPathManager; diff --git a/ghost/settings-path-manager/package.json b/ghost/settings-path-manager/package.json new file mode 100644 index 0000000000..afd722fbae --- /dev/null +++ b/ghost/settings-path-manager/package.json @@ -0,0 +1,30 @@ +{ + "name": "@tryghost/settings-path-manager", + "version": "0.0.0", + "repository": "https://github.com/TryGhost/Utils/tree/main/packages/settings-path-manager", + "author": "Ghost Foundation", + "license": "MIT", + "main": "index.js", + "scripts": { + "dev": "echo \"Implement me!\"", + "test": "NODE_ENV=testing c8 --check-coverage mocha './test/**/*.test.js'", + "lint": "eslint . --ext .js --cache", + "posttest": "yarn lint" + }, + "files": [ + "index.js", + "lib" + ], + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "c8": "7.9.0", + "mocha": "9.1.2", + "should": "13.2.3", + "sinon": "11.1.2" + }, + "dependencies": { + "tpl": "^0.3.0" + } +} diff --git a/ghost/settings-path-manager/test/.eslintrc.js b/ghost/settings-path-manager/test/.eslintrc.js new file mode 100644 index 0000000000..829b601eb0 --- /dev/null +++ b/ghost/settings-path-manager/test/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: ['ghost'], + extends: [ + 'plugin:ghost/test' + ] +}; diff --git a/ghost/settings-path-manager/test/settings-path-manager.test.js b/ghost/settings-path-manager/test/settings-path-manager.test.js new file mode 100644 index 0000000000..d7134fd38a --- /dev/null +++ b/ghost/settings-path-manager/test/settings-path-manager.test.js @@ -0,0 +1,57 @@ +// Switch these lines once there are useful utils +// const testUtils = require('./utils'); +require('./utils'); +const should = require('should'); +const SettingsPathManager = require('../'); + +describe('Settings Path Manager', function () { + it('throws when paths parameter is not provided', function () { + try { + const settingsPathManager = new SettingsPathManager({ + paths: [], + type: 'routes' + }); + + should.fail(settingsPathManager, 'Should have errored'); + } catch (err) { + should.exist(err); + err.message.should.match(/paths values/g); + } + }); + + describe('getDefaultFilePath', function () { + it('returns default file path based on routes configuration', function (){ + const settingsPathManager = new SettingsPathManager({ + paths: ['/content/settings', '/content/data'], + type: 'routes' + }); + + const path = settingsPathManager.getDefaultFilePath(); + + path.should.equal('/content/settings/routes.yaml'); + }); + + it('returns default file path based on redirects configuration', function (){ + const settingsPathManager = new SettingsPathManager({ + paths: ['/content/data', '/content/settings'], + type: 'redirects' + }); + + const path = settingsPathManager.getDefaultFilePath(); + + path.should.equal('/content/data/redirects.yaml'); + }); + + it('returns default file path based on redirects configuration with json extension', function (){ + const settingsPathManager = new SettingsPathManager({ + paths: ['/content/data', '/content/settings'], + type: 'redirects', + extensions: ['json', 'yaml'] + }); + + const path = settingsPathManager.getDefaultFilePath(); + + path.should.equal('/content/data/redirects.json'); + }); + }); +}); diff --git a/ghost/settings-path-manager/test/utils/assertions.js b/ghost/settings-path-manager/test/utils/assertions.js new file mode 100644 index 0000000000..7364ee8aa1 --- /dev/null +++ b/ghost/settings-path-manager/test/utils/assertions.js @@ -0,0 +1,11 @@ +/** + * Custom Should Assertions + * + * Add any custom assertions to this file. + */ + +// Example Assertion +// should.Assertion.add('ExampleAssertion', function () { +// this.params = {operator: 'to be a valid Example Assertion'}; +// this.obj.should.be.an.Object; +// }); diff --git a/ghost/settings-path-manager/test/utils/index.js b/ghost/settings-path-manager/test/utils/index.js new file mode 100644 index 0000000000..0d67d86ff8 --- /dev/null +++ b/ghost/settings-path-manager/test/utils/index.js @@ -0,0 +1,11 @@ +/** + * Test Utilities + * + * Shared utils for writing tests + */ + +// Require overrides - these add globals for tests +require('./overrides'); + +// Require assertions - adds custom should assertions +require('./assertions'); diff --git a/ghost/settings-path-manager/test/utils/overrides.js b/ghost/settings-path-manager/test/utils/overrides.js new file mode 100644 index 0000000000..90203424ee --- /dev/null +++ b/ghost/settings-path-manager/test/utils/overrides.js @@ -0,0 +1,10 @@ +// This file is required before any test is run + +// Taken from the should wiki, this is how to make should global +// Should is a global in our eslint test config +global.should = require('should').noConflict(); +should.extend(); + +// Sinon is a simple case +// Sinon is a global in our eslint test config +global.sinon = require('sinon');