diff --git a/src/create.js b/src/create.js index 6bf3f0a..2147e27 100644 --- a/src/create.js +++ b/src/create.js @@ -78,7 +78,7 @@ async function main() { // options for site .option('--import-site ', 'URL of site to import') - .option('--import-structure ', `import method to use:\n\rpressbooksToSite\n\relmslnToSite\n\rhaxcmsToSite\n\rnotionToSite\n\rgitbookToSite\n\revolutionToSite\n\rploneToSite\n\rwordpressPagesToSite\n\rdrupalBookToSite\n\rhtmlToSite\n\rdocxToSite`) + .option('--import-structure ', `import method to use:\n\rpressbooksToSite\n\relmslnToSite\n\rhaxcmsToSite\n\rnotionToSite\n\rgitbookToSite\n\revolutionToSite\n\rploneToSite\n\rwordpressPagesToSite\n\rdrupalBookToSite\n\ropenstaxToSite\n\rhtmlToSite\n\rdocxToSite\n\rxlsxToSite`) .option('--node-op ', 'node operation to perform') .option('--item-id ', 'node ID to operate on') .option('--domain ', 'published domain name') @@ -192,7 +192,7 @@ async function main() { .option('--root ', 'root location to execute the command from') .option('--import-site ', 'URL of site to import') - .option('--import-structure ', `import method to use:\n\rpressbooksToSite\n\relmslnToSite\n\rhaxcmsToSite\n\rnotionToSite\n\rgitbookToSite\n\revolutionToSite\n\rploneToSite\n\rwordpressPagesToSite\n\rdrupalBookToSite\n\rhtmlToSite\n\rdocxToSite`) + .option('--import-structure ', `import method to use:\n\rpressbooksToSite\n\relmslnToSite\n\rhaxcmsToSite\n\rnotionToSite\n\rgitbookToSite\n\revolutionToSite\n\rploneToSite\n\rwordpressPagesToSite\n\rdrupalBookToSite\n\ropenstaxToSite\n\rhtmlToSite\n\rdocxToSite\n\rxlsxToSite`) .option('--name ', 'name of the site (when creating a new one)') .option('--domain ', 'published domain name') .option('--node-op ', 'node operation to perform') diff --git a/src/docs/hax.1 b/src/docs/hax.1 index ad6e9cd..00e1848 100644 --- a/src/docs/hax.1 +++ b/src/docs/hax.1 @@ -225,9 +225,13 @@ wordpressPagesToSite .br drupalBookToSite .br +openstaxToSite +.br htmlToSite .br docxToSite +.br +xlsxToSite .TP \--node\-op node operation to perform diff --git a/src/lib/programs/site.js b/src/lib/programs/site.js index 6b38b8a..88295af 100644 --- a/src/lib/programs/site.js +++ b/src/lib/programs/site.js @@ -182,7 +182,7 @@ async function invokeRoute(routeHandler, body = {}, query = {}, params = {}) { // converters go through the site/import/:platform dispatcher; docx/xlsx use their // own actions routes. evolutionToSite (custom zip upload) is intentionally absent // and falls through to the hidden-methodologies branch below. -const IMPORT_STRUCTURE_MAP = { +export const IMPORT_STRUCTURE_MAP = { haxcmsToSite: { platform: 'haxcms' }, pressbooksToSite: { platform: 'pressbooks' }, gitbookToSite: { platform: 'gitbook' }, @@ -191,6 +191,7 @@ const IMPORT_STRUCTURE_MAP = { ploneToSite: { platform: 'plone' }, wordpressPagesToSite: { platform: 'wordpress' }, drupalBookToSite: { platform: 'drupal-book' }, + openstaxToSite: { platform: 'openstax' }, htmlToSite: { platform: 'html' }, docxToSite: { routeKey: 'actions/import-docx' }, xlsxToSite: { routeKey: 'actions/import-xlsx' }, diff --git a/test/unit/site-imports.test.cjs b/test/unit/site-imports.test.cjs new file mode 100644 index 0000000..51981d9 --- /dev/null +++ b/test/unit/site-imports.test.cjs @@ -0,0 +1,66 @@ +'use strict' + +// Isolate HOME BEFORE requiring site.js (via the canary) so HAXCMS init lands in +// a temp dir, not the real ~/.haxtheweb. Same pattern as site-helpers-2.test.cjs. +const fs = require('node:fs') +const os = require('node:os') +const path = require('node:path') +const ISOLATED_HOME = fs.mkdtempSync(path.join(os.tmpdir(), 'hax-site-imports-')) +process.env.HOME = ISOLATED_HOME +process.env.USERPROFILE = ISOLATED_HOME + +const test = require('node:test') +const assert = require('node:assert/strict') + +const { available, skipReason, module: siteModule } = require('../_helpers/site-canary.cjs') + +const { IMPORT_STRUCTURE_MAP } = available ? siteModule : {} + +const opts = { skip: skipReason, timeout: 15000 } + +// --- IMPORT_STRUCTURE_MAP --- +// --import-structure names resolve to on-prem haxcms-nodejs routes: platform +// converters through the site/import/:platform dispatcher, docx/xlsx through +// their own actions routes. A converter missing from this map is unreachable +// from the CLI even when the backend route exists, which is what happened to +// the OpenStax importer from haxtheweb/issues#2912. + +test('every platform importer maps to its dispatcher platform', opts, () => { + const platforms = {} + Object.keys(IMPORT_STRUCTURE_MAP).forEach((name) => { + if (IMPORT_STRUCTURE_MAP[name].platform) { + platforms[name] = IMPORT_STRUCTURE_MAP[name].platform + } + }) + assert.deepEqual(platforms, { + haxcmsToSite: 'haxcms', + pressbooksToSite: 'pressbooks', + gitbookToSite: 'gitbook', + notionToSite: 'notion', + elmslnToSite: 'elmsln', + ploneToSite: 'plone', + wordpressPagesToSite: 'wordpress', + drupalBookToSite: 'drupal-book', + openstaxToSite: 'openstax', + htmlToSite: 'html', + }) +}) + +test('openstaxToSite reaches the openstax dispatcher case', opts, () => { + assert.deepEqual(IMPORT_STRUCTURE_MAP.openstaxToSite, { platform: 'openstax' }) +}) + +test('docx and xlsx keep their own action routes', opts, () => { + assert.deepEqual(IMPORT_STRUCTURE_MAP.docxToSite, { routeKey: 'actions/import-docx' }) + assert.deepEqual(IMPORT_STRUCTURE_MAP.xlsxToSite, { routeKey: 'actions/import-xlsx' }) +}) + +test('the --import-structure help and man page list every mapped importer', opts, () => { + const root = path.join(__dirname, '..', '..') + const help = fs.readFileSync(path.join(root, 'src', 'create.js'), 'utf8') + const manPage = fs.readFileSync(path.join(root, 'src', 'docs', 'hax.1'), 'utf8') + Object.keys(IMPORT_STRUCTURE_MAP).forEach((name) => { + assert.ok(help.includes(name), name + ' is offered by --import-structure') + assert.ok(manPage.includes(name), name + ' is documented in the man page') + }) +})