Files
wordpress-export-to-markdown/src/wizard.js
T
2025-01-18 14:22:53 -05:00

197 lines
4.4 KiB
JavaScript

import camelcase from 'camelcase';
import * as commander from 'commander';
import fs from 'fs';
import inquirer from 'inquirer';
import path from 'path';
// all user options for command line and wizard are declared here
const options = [
// wizard must always be first
{
name: 'wizard',
type: 'boolean',
description: 'Use wizard',
default: true
},
{
name: 'input',
type: 'file',
description: 'Path to WordPress export file',
default: 'export.xml'
},
{
name: 'output',
type: 'folder',
description: 'Path to output folder',
default: 'output'
},
{
name: 'year-folders',
aliases: ['yearfolders', 'yearmonthfolders'],
type: 'boolean',
description: 'Create year folders',
default: false
},
{
name: 'month-folders',
aliases: ['yearmonthfolders'],
type: 'boolean',
description: 'Create month folders',
default: false
},
{
name: 'post-folders',
aliases: ['postfolders'],
type: 'boolean',
description: 'Create a folder for each post',
default: true
},
{
name: 'prefix-date',
aliases: ['prefixdate'],
type: 'boolean',
description: 'Prefix post folders/files with date',
default: false
},
{
name: 'save-attached-images',
aliases: ['saveimages'],
type: 'boolean',
description: 'Save images attached to posts',
default: true
},
{
name: 'save-scraped-images',
aliases: ['addcontentimages'],
type: 'boolean',
description: 'Save images scraped from post body content',
default: true
},
{
name: 'include-other-types',
type: 'boolean',
description: 'Include custom post types and pages',
default: false
}
];
export async function getConfig(argv) {
extendOptionsData();
const unaliasedArgv = replaceAliases(argv);
const opts = parseCommandLine(unaliasedArgv);
let answers;
if (opts.wizard) {
console.log('\nStarting wizard...');
const questions = options.map(option => ({
when: option.name !== 'wizard' && !option.isProvided,
name: camelcase(option.name),
type: option.prompt,
message: option.description + '?',
default: option.default,
// these are not used for all option types and that's fine
filter: option.coerce,
validate: option.validate
}));
answers = await inquirer.prompt(questions);
} else {
console.log('\nSkipping wizard...');
answers = {};
}
const config = { ...opts, ...answers };
return config;
}
function extendOptionsData() {
// add more data to each option based on its type
const map = {
boolean: {
prompt: 'confirm',
coerce: coerceBoolean,
},
file: {
prompt: 'input',
coerce: coercePath,
validate: validateFile
},
folder: {
prompt: 'input',
coerce: coercePath
}
};
options.forEach(option => {
Object.assign(option, map[option.type]);
});
}
function replaceAliases(argv) {
let paths = argv.slice(0, 2);
let replaced = [];
let unmodified = [];
argv.slice(2).forEach(arg => {
let aliasFound = false;
// this loop does not short circuit because an alias can map to multiple options
options.forEach(option => {
const aliases = option.aliases || [];
aliases.forEach(alias => {
if (arg.includes('--' + alias)) {
replaced.push(arg.replace('--' + alias, '--' + option.name));
aliasFound = true;
}
});
});
if (!aliasFound) {
unmodified.push(arg);
}
});
return [...paths, ...replaced, ...unmodified];
}
function parseCommandLine(argv) {
// setup for help output
commander.program
.name('node index.js')
.helpOption('-h, --help', 'See the thing you\'re looking at right now')
.addHelpText('after', '\nMore documentation is at https://github.com/lonekorean/wordpress-export-to-markdown');
options.forEach(input => {
const flag = '--' + input.name + ' <' + input.type + '>';
const coerce = (value) => {
// commander only calls coerce when an input is provided on the command line, which
// makes for an easy way to flag (for later) if it should be excluded from the wizard
input.isProvided = true;
return input.coerce(value);
};
commander.program.option(flag, input.description, coerce, input.default);
});
commander.program.parse(argv);
return commander.program.opts();
}
function coerceBoolean(value) {
return !['false', 'no', '0'].includes(value.toString().toLowerCase());
}
function coercePath(value) {
return path.normalize(value);
}
function validateFile(value) {
let isValid;
try {
isValid = fs.existsSync(value) && fs.statSync(value).isFile();
} catch (ex) {
isValid = false;
}
return isValid ? true : 'Unable to find file: ' + path.resolve(value);
}