@swell/cli
Version:
Swell's command line interface/utility
167 lines (166 loc) • 4.95 kB
JavaScript
/**
* App configuration for local development of Swell Apps.
*/
import Conf from 'conf';
import * as fs from 'node:fs';
import * as path from 'node:path';
const schema = {
compatibilities: { type: 'object' },
description: { type: 'string' },
extensions: { type: 'array' },
id: { type: 'string' },
integrations: { type: 'array' },
name: { type: 'string' },
permissions: { type: 'array' },
storefront: { type: 'object' },
theme: { type: 'object' },
type: { type: 'string' },
version: { type: 'string' },
};
const APP_FILE_NAME = 'swell';
const APP_FILE_EXT = 'json';
/**
* Builds the path to the app config file. If no directory is provided, the
* current working directory is used.
*
* @param dir - the directory to use for the config file path
* @returns string
*/
function swellConfigFile(dir = '') {
if (!dir) {
dir = process.cwd();
}
return path.join(dir, [APP_FILE_NAME, '.', APP_FILE_EXT].join(''));
}
/**
* Checks if the swell config file exists at the given path, default to cwd.
*
* @param configFilePath - the path to the app config file
* @returns boolean
* @throws Error
*/
function swellConfigFileExists(configFilePath = '') {
// if the config file path is not provided, try to find it as the default
if (!configFilePath) {
configFilePath = swellConfigFile();
}
try {
// eslint-disable-next-line no-bitwise
fs.accessSync(configFilePath, fs.constants.R_OK | fs.constants.W_OK);
return true;
}
catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
return false;
}
}
/**
* Finds the app config file in the current directory or a parent directory.
* If the file is not found, an error is thrown.
*
* @param dir - the directory to start searching from
* @returns string
* @throws Error
*/
function swellConfigFilePath(dir = '') {
const configFilePath = swellConfigFile(dir);
if (swellConfigFileExists(configFilePath)) {
return configFilePath;
}
// if the file doesn't exist, try to find it in the parent directory
// until we reach the root directory
if (dir && dir === path.parse(dir).root) {
return '';
}
return swellConfigFilePath(path.resolve(dir, '..'));
}
async function writeRcFile(path, data) {
let dataToWrite = '# This file is automatically generated by the Swell CLI\n';
for (const [key, value] of Object.entries(data)) {
dataToWrite += `${key}=${value}\n`;
}
fs.writeFileSync(path, dataToWrite);
}
function readRcFile(path) {
const data = {};
const dataFromFile = fs.readFileSync(path, 'utf8');
const lines = dataFromFile.split('\n');
for (const line of lines) {
const cleanLine = line.trim();
if (cleanLine.startsWith('#')) {
// Ignore comments
continue;
}
const [key, value] = cleanLine.trim().split('=');
const cleanValue = value && value.trim();
if (key && cleanValue) {
data[key] = cleanValue;
}
}
return data;
}
/**
* Returns a new configuration instance in the current working directory or
* a parent directory.
*
* @param configDir - the path to the app config directory. If not provided,
* the config file will be searched for in the current working directory or
* a parent directory.
*
* @returns Conf
*/
function config(configDir = '') {
const dirPath = configDir || path.dirname(swellConfigFilePath());
let config;
try {
config = new Conf({
clearInvalidConfig: true,
configName: APP_FILE_NAME,
cwd: dirPath,
schema,
});
}
catch (error) {
throw new Error(`Error parsing swell.json: ${error.toString()}`);
}
// for convenience, we add custom properties to the Conf object
// we prefix them with "sw" to avoid conflicts with Conf's properties
config.swDirPath = dirPath;
return config;
}
/**
* Returns a new configuration instance in the current working directory only.
*
* @param path Path of the current working directory
* @returns Conf
*/
function newConfig(path) {
return new Conf({
clearInvalidConfig: true,
configName: APP_FILE_NAME,
cwd: `${process.cwd()}${path ? `/${path}` : ''}`,
schema,
serialize,
});
}
/**
* Returns a new configuration instance at the specified path.
*
* @param appPath Path of the current working directory
* @returns Conf
*/
function newConfigAtPath(appPath) {
const dirPath = appPath || path.dirname(swellConfigFilePath());
return new Conf({
configName: APP_FILE_NAME,
cwd: dirPath,
schema,
serialize,
});
}
function serialize(value) {
return JSON.stringify(value, null, 2);
}
export { config as default, newConfig, newConfigAtPath, readRcFile, swellConfigFileExists, writeRcFile, };