From 3201f4cc62c870f6428e03de0fdb834099adba10 Mon Sep 17 00:00:00 2001 From: Connor Anderson Date: Mon, 15 Mar 2021 13:24:04 -0400 Subject: [PATCH] Update the custom card commands and add the add vertical command for theme v1.16 --- .../commands/addvertical.js | 148 ++++++++++++++++++ .../commands/cardcreator.js | 37 ++--- .../commands/directanswercardcreator.js | 36 ++--- .../helpers/utils/jamboconfigutils.js | 16 +- 4 files changed, 191 insertions(+), 46 deletions(-) create mode 100644 themes/answers-hitchhiker-theme/commands/addvertical.js diff --git a/themes/answers-hitchhiker-theme/commands/addvertical.js b/themes/answers-hitchhiker-theme/commands/addvertical.js new file mode 100644 index 0000000..7343cb6 --- /dev/null +++ b/themes/answers-hitchhiker-theme/commands/addvertical.js @@ -0,0 +1,148 @@ +const fs = require('fs-extra'); +const path = require('path'); +const { spawnSync } = require('child_process'); + +const UserError = require('./helpers/errors/usererror'); +const { ArgumentMetadata, ArgumentType } = require('./helpers/utils/argumentmetadata'); + +/** + * VerticalAdder represents the `vertical` custom jambo command. The command adds + * a new page for the given Vertical and associates a card type with it. + */ +class VerticalAdder { + constructor(jamboConfig) { + this.config = jamboConfig; + } + + /** + * @returns {string} the alias for the add vertical command. + */ + static getAlias() { + return 'vertical'; + } + + /** + * @returns {string} a short description of the add vertical command. + */ + static getShortDescription() { + return 'create the page for a vertical'; + } + + /** + * @returns {Object} description of each argument for + * the add vertical command, keyed by name + */ + static args() { + return { + name: new ArgumentMetadata(ArgumentType.STRING, 'name of the vertical\'s page', true), + verticalKey: new ArgumentMetadata(ArgumentType.STRING, 'the vertical\'s key', true), + cardName: new ArgumentMetadata( + ArgumentType.STRING, 'card to use with vertical', false, 'standard'), + template: new ArgumentMetadata( + ArgumentType.STRING, 'page template to use within theme', true) + }; + } + + /** + * @returns {Object} description of the vertical command and its parameters. + */ + static describe(jamboConfig) { + return { + displayName: 'Add Vertical', + params: { + name: { + displayName: 'Page Name', + required: true, + type: 'string' + }, + verticalKey: { + displayName: 'Vertical Key', + required: true, + type: 'string', + }, + cardName: { + displayName: 'Card Name', + type: 'singleoption', + options: this._getAvailableCards(jamboConfig) + }, + template: { + displayName: 'Page Template', + required: true, + type: 'singleoption', + options: this._getPageTemplates(jamboConfig) + } + } + }; + } + + /** + * @returns {Array} the names of the available cards in the Theme + */ + static _getAvailableCards(jamboConfig) { + const defaultTheme = jamboConfig.defaultTheme; + const themesDir = jamboConfig.dirs && jamboConfig.dirs.themes; + if (!defaultTheme || !themesDir) { + return []; + } + const cardsDir = path.join(themesDir, defaultTheme, 'cards'); + return fs.readdirSync(cardsDir, { withFileTypes: true }) + .filter(dirent => !dirent.isFile()) + .map(dirent => dirent.name); + } + + /** + * @returns {Array} The page templates available in the current theme + */ + static _getPageTemplates(jamboConfig) { + const defaultTheme = jamboConfig.defaultTheme; + const themesDir = jamboConfig.dirs && jamboConfig.dirs.themes; + if (!defaultTheme || !themesDir) { + return []; + } + const pageTemplatesDir = path.resolve(themesDir, defaultTheme, 'templates'); + return fs.readdirSync(pageTemplatesDir); + } + + /** + * Executes the add vertical command with the provided arguments. + * + * @param {Object} args The arguments, keyed by name + */ + execute(args) { + if (!VerticalAdder._getAvailableCards(this.config).includes(args.cardName)) { + throw new UserError(`${args.cardName} is not a valid card`); + } + + this._createVerticalPage(args.name, args.template); + this._configureVerticalPage(args.name, args.verticalKey, args.cardName); + } + + /** + * Creates a page for the vertical using the provided name and template. Any output from + * the `jambo page` command is piped through. + * + * @param {string} name The name of the vertical's page. + * @param {string} template The template to use. + */ + _createVerticalPage(name, template) { + const args = ['--name', name, '--template', template]; + spawnSync('npx jambo page', args, { shell: true, stdio: 'inherit' }); + } + + /** + * Updates the vertical page's configuration file. Specifically, placeholders for + * vertical key and card type are replaced with the provided values. + * + * @param {string} name The page name. + * @param {string} verticalKey The vertical's key. + * @param {string} cardName The card to be used with the vertical. + */ + _configureVerticalPage(name, verticalKey, cardName) { + const configFile = `config/${name}.json`; + let parsedConfig = fs.readFileSync(configFile, { encoding: 'utf-8' }); + parsedConfig = parsedConfig.replace(/\/g, verticalKey); + parsedConfig = parsedConfig.replace(/"cardType": "[^,]+"/, `"cardType": "${cardName}"`); + fs.writeFileSync(configFile, parsedConfig); + } +} +module.exports = VerticalAdder; diff --git a/themes/answers-hitchhiker-theme/commands/cardcreator.js b/themes/answers-hitchhiker-theme/commands/cardcreator.js index 7174819..33c1c6a 100644 --- a/themes/answers-hitchhiker-theme/commands/cardcreator.js +++ b/themes/answers-hitchhiker-theme/commands/cardcreator.js @@ -1,5 +1,5 @@ const fs = require('fs-extra'); -const { addToPartials } = require('./helpers/utils/jamboconfigutils'); +const { containsPartial, addToPartials } = require('./helpers/utils/jamboconfigutils'); const path = require('path'); const UserError = require('./helpers/errors/usererror'); const { ArgumentMetadata, ArgumentType } = require('./helpers/utils/argumentmetadata'); @@ -12,22 +12,20 @@ const { ArgumentMetadata, ArgumentType } = require('./helpers/utils/argumentmeta class CardCreator { constructor(jamboConfig) { this.config = jamboConfig; - this.themesDir = jamboConfig.dirs && jamboConfig.dirs.themes; - this.defaultTheme = jamboConfig.defaultTheme; this._customCardsDir = 'cards'; } /** * @returns {string} the alias for the create card command. */ - getAlias() { + static getAlias() { return 'card'; } /** * @returns {string} a short description of the create card command. */ - getShortDescription() { + static getShortDescription() { return 'add a new card for use in the site'; } @@ -35,7 +33,7 @@ class CardCreator { * @returns {Object} description of each argument for * the create card command, keyed by name */ - args() { + static args() { return { 'name': new ArgumentMetadata(ArgumentType.STRING, 'name for the new card', true), 'templateCardFolder': new ArgumentMetadata(ArgumentType.STRING, 'folder of card to fork', true) @@ -46,8 +44,8 @@ class CardCreator { * @returns {Object} description of the card command, including paths to * all available cards */ - describe() { - const cardPaths = this._getCardPaths(); + static describe(jamboConfig) { + const cardPaths = this._getCardPaths(jamboConfig); return { displayName: 'Add Card', params: { @@ -69,11 +67,13 @@ class CardCreator { /** * @returns {Array} the paths of the available cards */ - _getCardPaths() { - if (!this.defaultTheme || !this.themesDir) { + static _getCardPaths(jamboConfig) { + const defaultTheme = jamboConfig.defaultTheme; + const themesDir = jamboConfig.dirs && jamboConfig.dirs.themes; + if (!defaultTheme || !themesDir) { return []; } - const cardsDir = path.join(this.themesDir, this.defaultTheme, 'cards'); + const cardsDir = path.join(themesDir, defaultTheme, 'cards'); return fs.readdirSync(cardsDir, { withFileTypes: true }) .filter(dirent => !dirent.isFile()) .map(dirent => path.join(cardsDir, dirent.name)); @@ -114,7 +114,8 @@ class CardCreator { const cardFolder = `${this._customCardsDir}/${cardFolderName}`; if (fs.existsSync(templateCardFolder)) { - !fs.existsSync(this._customCardsDir) && this._createCustomCardsDir(); + !fs.existsSync(this._customCardsDir) && fs.mkdirSync(this._customCardsDir); + !containsPartial(this._customCardsDir) && addToPartials(this._customCardsDir); fs.copySync(templateCardFolder, cardFolder); this._renameCardComponent(cardFolderName, cardFolder); } else { @@ -155,15 +156,5 @@ class CardCreator { .replace(new RegExp(originalComponentName, 'g'), customCardName) .replace(/cards[/_](.*)[/_]template/g, `cards/${customCardName}/template`); } - - /** - * Creates the 'cards' directory in the Jambo repository and adds the newly - * created directory to the list of partials in the Jambo config. - */ - _createCustomCardsDir() { - fs.mkdirSync(this._customCardsDir); - addToPartials(this._customCardsDir); - } } - -module.exports = jamboConfig => new CardCreator(jamboConfig); +module.exports = CardCreator; diff --git a/themes/answers-hitchhiker-theme/commands/directanswercardcreator.js b/themes/answers-hitchhiker-theme/commands/directanswercardcreator.js index fc98e22..7658ca6 100644 --- a/themes/answers-hitchhiker-theme/commands/directanswercardcreator.js +++ b/themes/answers-hitchhiker-theme/commands/directanswercardcreator.js @@ -1,5 +1,5 @@ const fs = require('fs-extra'); -const { addToPartials } = require('./helpers/utils/jamboconfigutils'); +const { containsPartial, addToPartials } = require('./helpers/utils/jamboconfigutils'); const path = require('path'); const UserError = require('./helpers/errors/usererror'); const { ArgumentMetadata, ArgumentType } = require('./helpers/utils/argumentmetadata'); @@ -12,22 +12,20 @@ const { ArgumentMetadata, ArgumentType } = require('./helpers/utils/argumentmeta class DirectAnswerCardCreator { constructor(jamboConfig) { this.config = jamboConfig; - this.themesDir = jamboConfig.dirs && jamboConfig.dirs.themes; - this.defaultTheme = jamboConfig.defaultTheme; this._customCardsDir = 'directanswercards'; } /** * @returns {string} the alias for the create direct answer card command. */ - getAlias() { + static getAlias() { return 'directanswercard'; } /** * @returns {string} a short description of the create direct answer card command. */ - getShortDescription() { + static getShortDescription() { return 'add a new direct answer card for use in the site'; } @@ -35,7 +33,7 @@ class DirectAnswerCardCreator { * @returns {Object} description of each argument for * the create direct answer card command, keyed by name */ - args() { + static args() { return { 'name': new ArgumentMetadata(ArgumentType.STRING, 'name for the new direct answer card', true), 'templateCardFolder': new ArgumentMetadata(ArgumentType.STRING, 'folder of direct answer card to fork', true) @@ -46,8 +44,8 @@ class DirectAnswerCardCreator { * @returns {Object} description of the direct answer card command, including paths to * all available direct answer cards */ - describe() { - const directAnswerCardPaths = this._getDirectAnswerCardPaths(); + static describe(jamboConfig) { + const directAnswerCardPaths = this._getDirectAnswerCardPaths(jamboConfig); return { displayName: 'Add Direct Answer Card', params: { @@ -69,11 +67,13 @@ class DirectAnswerCardCreator { /** * @returns {Array} the paths of the available direct answer cards */ - _getDirectAnswerCardPaths() { - if (!this.defaultTheme || !this.themesDir) { + static _getDirectAnswerCardPaths(jamboConfig) { + const defaultTheme = jamboConfig.defaultTheme; + const themesDir = jamboConfig.dirs && jamboConfig.dirs.themes; + if (!defaultTheme || !themesDir) { return []; } - const daCardsDir = path.join(this.themesDir, this.defaultTheme, 'directanswercards'); + const daCardsDir = path.join(themesDir, defaultTheme, 'directanswercards'); return fs.readdirSync(daCardsDir, { withFileTypes: true }) .filter(dirent => !dirent.isFile()) .map(dirent => path.join(daCardsDir, dirent.name)); @@ -114,7 +114,8 @@ class DirectAnswerCardCreator { const cardFolder = `${this._customCardsDir}/${cardFolderName}`; if (fs.existsSync(templateCardFolder)) { - !fs.existsSync(this._customCardsDir) && this._createCustomCardsDir(); + !fs.existsSync(this._customCardsDir) && fs.mkdirSync(this._customCardsDir); + !containsPartial(this._customCardsDir) && addToPartials(this._customCardsDir); fs.copySync(templateCardFolder, cardFolder); this._renameCardComponent(cardFolderName, cardFolder); } else { @@ -159,15 +160,6 @@ class DirectAnswerCardCreator { /directanswercards[/_](.*)[/_]template/g, `directanswercards/${customCardName}/template`); } - - /** - * Creates the 'directanswercards' directory in the Jambo repository and adds the newly - * created directory to the list of partials in the Jambo config. - */ - _createCustomCardsDir() { - fs.mkdirSync(this._customCardsDir); - addToPartials(this._customCardsDir); - } } -module.exports = jamboConfig => new DirectAnswerCardCreator(jamboConfig); +module.exports = DirectAnswerCardCreator; diff --git a/themes/answers-hitchhiker-theme/commands/helpers/utils/jamboconfigutils.js b/themes/answers-hitchhiker-theme/commands/helpers/utils/jamboconfigutils.js index 2e91f22..c356cba 100644 --- a/themes/answers-hitchhiker-theme/commands/helpers/utils/jamboconfigutils.js +++ b/themes/answers-hitchhiker-theme/commands/helpers/utils/jamboconfigutils.js @@ -52,4 +52,18 @@ exports.addToPartials = function (partialsPath) { existingPartials.push(partialsPath); fs.writeFileSync('jambo.json', stringify(jamboConfig, null, 2)); } -} \ No newline at end of file +} + +/** + * Returns whether or not the partialsPath exists in the partials object in the + * Jambo config + * + * @param {Object} jamboConfig The parsed jambo config + * @param {string} partialsPath The local path to the set of partials. + * @returns {boolean} + */ +exports.containsPartial = function (jamboConfig, partialsPath) { + return jamboConfig.dirs + && jamboConfig.dirs.partials + && jamboConfig.dirs.partials.includes(partialsPath); +} -- 2.30.2