webcm
Version:
Demonstrative implementation of a web-based manager for utilising Managed Components
140 lines (123 loc) • 4.08 kB
text/typescript
/* eslint-disable no-console */
import yargs from 'yargs'
import { startServerFromConfig } from './server'
import { hideBin } from 'yargs/helpers'
import _locreq from 'locreq'
const locreq = _locreq(__dirname)
import nodeCrypto from 'crypto'
if (!Object.prototype.hasOwnProperty.call(globalThis, 'crypto')) {
globalThis.crypto = nodeCrypto.webcrypto as any
}
/**
* @fileoverview Main CLI that is run via the webcm command.
*/
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
* Get the error message of a given value.
*/
function getErrorMessage(error: Record<string, unknown>) {
// Lazy loading because this is used only if an error happened.
const util = require('util')
// Foolproof -- third-party module might throw non-object.
if (typeof error !== 'object' || error === null) {
return String(error)
}
// Use templates if `error.messageTemplate` is present.
if (typeof error.messageTemplate === 'string') {
try {
const template = require(`../messages/${error.messageTemplate}.js`)
return template(error.messageData || {})
} catch {
// Ignore template error then fallback to use `error.stack`.
}
}
// Use the stacktrace if it's an error object.
if (typeof error.stack === 'string') {
return error.stack
}
// Otherwise, dump the object.
return util.format('%o', error)
}
/**
* Catch and report unexpected error.
*/
function onFatalError(error: Record<string, unknown>) {
process.exitCode = 2
const message = getErrorMessage(error)
console.error(`
Oops! Something went wrong! :(
Webcm: ${locreq('package.json').version}
${message}`)
}
//------------------------------------------------------------------------------
// Execution
//------------------------------------------------------------------------------
;(async function main() {
process.on('uncaughtException', onFatalError)
process.on('unhandledRejection', onFatalError)
const options = {
config: <const>{
alias: 'c',
type: 'string',
describe: 'path to your Managed Components config',
},
components: <const>{
alias: 'mc',
type: 'string',
default: './components',
describe: 'path to Managed Components folder',
},
}
yargs(hideBin(process.argv))
.options(options)
.command(
'$0 [customComponentPath] [target]',
'proxy a demo website and load the specified component on it',
yargs => {
return yargs
.positional('customComponentPath', {
type: 'string',
description: 'the path to the entrypoint of your component',
})
.positional('target', {
type: 'string',
describe: 'the http url to direct the proxy to',
})
},
argv => {
const customSettings: Record<string, string> = Object.fromEntries(
Object.entries(argv)
.filter(([key]) => key.startsWith('settings_'))
.map(([key, value]) => [
key.replace(/^settings_/, ''),
String(value),
])
)
if (Object.keys(customSettings).length && !argv.customComponentPath) {
console.log(
`Error: custom settings (${Object.keys(customSettings).join(
', '
)}) passed, but no custom component specified. To use a custom component, specify the 'customComponentPath' positional argument\n\n`
)
yargs.showHelp()
return
}
require('ts-node').register({
files: true,
transpileOnly: true,
dir: __dirname,
})
startServerFromConfig({
configPath: argv.config,
componentsFolderPath: argv.components,
customComponentPath: argv.customComponentPath,
customComponentSettings: customSettings,
url: argv.target,
})
}
)
.parse()
})().catch(onFatalError)