UNPKG

highcharts-export-server

Version:

Convert Highcharts.JS charts into static image files.

1,175 lines (1,160 loc) 33.8 kB
/******************************************************************************* Highcharts Export Server Copyright (c) 2016-2024, Highsoft Licenced under the MIT licence. Additionally a valid Highcharts license is required for use. See LICENSE file in root for details. *******************************************************************************/ // Possible names for Highcharts scripts export const scriptsNames = { core: ['highcharts', 'highcharts-more', 'highcharts-3d'], modules: [ 'stock', 'map', 'gantt', 'exporting', 'parallel-coordinates', 'accessibility', // 'annotations-advanced', 'boost-canvas', 'boost', 'data', 'data-tools', 'draggable-points', 'static-scale', 'broken-axis', 'heatmap', 'tilemap', 'tiledwebmap', 'timeline', 'treemap', 'treegraph', 'item-series', 'drilldown', 'histogram-bellcurve', 'bullet', 'funnel', 'funnel3d', 'geoheatmap', 'pyramid3d', 'networkgraph', 'overlapping-datalabels', 'pareto', 'pattern-fill', 'pictorial', 'price-indicator', 'sankey', 'arc-diagram', 'dependency-wheel', 'series-label', 'series-on-point', 'solid-gauge', 'sonification', // 'stock-tools', 'streamgraph', 'sunburst', 'variable-pie', 'variwide', 'vector', 'venn', 'windbarb', 'wordcloud', 'xrange', 'no-data-to-display', 'drag-panes', 'debugger', 'dumbbell', 'lollipop', 'cylinder', 'organization', 'dotplot', 'marker-clusters', 'hollowcandlestick', 'heikinashi', 'flowmap', 'export-data', 'navigator', 'textpath' ], indicators: ['indicators-all'], custom: [ 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js' ] }; // This is the configuration object with all options and their default values, // also from the .env file if one exists export const defaultConfig = { puppeteer: { args: { value: [ '--allow-running-insecure-content', '--ash-no-nudges', '--autoplay-policy=user-gesture-required', '--block-new-web-contents', '--disable-accelerated-2d-canvas', '--disable-background-networking', '--disable-background-timer-throttling', '--disable-backgrounding-occluded-windows', '--disable-breakpad', '--disable-checker-imaging', '--disable-client-side-phishing-detection', '--disable-component-extensions-with-background-pages', '--disable-component-update', '--disable-default-apps', '--disable-dev-shm-usage', '--disable-domain-reliability', '--disable-extensions', '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP', '--disable-hang-monitor', '--disable-ipc-flooding-protection', '--disable-logging', '--disable-notifications', '--disable-offer-store-unmasked-wallet-cards', '--disable-popup-blocking', '--disable-print-preview', '--disable-prompt-on-repost', '--disable-renderer-backgrounding', '--disable-search-engine-choice-screen', '--disable-session-crashed-bubble', '--disable-setuid-sandbox', '--disable-site-isolation-trials', '--disable-speech-api', '--disable-sync', '--enable-unsafe-webgpu', '--hide-crash-restore-bubble', '--hide-scrollbars', '--metrics-recording-only', '--mute-audio', '--no-default-browser-check', '--no-first-run', '--no-pings', '--no-sandbox', '--no-startup-window', '--no-zygote', '--password-store=basic', '--process-per-tab', '--use-mock-keychain' ], type: 'string[]', description: 'Arguments array to send to Puppeteer.' } }, highcharts: { version: { value: 'latest', type: 'string', envLink: 'HIGHCHARTS_VERSION', description: 'The Highcharts version to be used.' }, cdnURL: { value: 'https://code.highcharts.com/', type: 'string', envLink: 'HIGHCHARTS_CDN_URL', description: 'The CDN URL for Highcharts scripts to be used.' }, coreScripts: { value: scriptsNames.core, type: 'string[]', envLink: 'HIGHCHARTS_CORE_SCRIPTS', description: 'The core Highcharts scripts to fetch.' }, moduleScripts: { value: scriptsNames.modules, type: 'string[]', envLink: 'HIGHCHARTS_MODULE_SCRIPTS', description: 'The modules of Highcharts to fetch.' }, indicatorScripts: { value: scriptsNames.indicators, type: 'string[]', envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS', description: 'The indicators of Highcharts to fetch.' }, customScripts: { value: scriptsNames.custom, type: 'string[]', description: 'Additional custom scripts or dependencies to fetch.' }, forceFetch: { value: false, type: 'boolean', envLink: 'HIGHCHARTS_FORCE_FETCH', description: 'The flag to determine whether to refetch all scripts after each server rerun.' }, cachePath: { value: '.cache', type: 'string', envLink: 'HIGHCHARTS_CACHE_PATH', description: 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.' } }, export: { infile: { value: false, type: 'string', description: 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.' }, instr: { value: false, type: 'string', description: 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.' }, options: { value: false, type: 'string', description: 'An alias for the --instr option.' }, outfile: { value: false, type: 'string', description: 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.' }, type: { value: 'png', type: 'string', envLink: 'EXPORT_TYPE', description: 'The file export format. It can be jpeg, png, pdf, or svg.' }, constr: { value: 'chart', type: 'string', envLink: 'EXPORT_CONSTR', description: 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.' }, defaultHeight: { value: 400, type: 'number', envLink: 'EXPORT_DEFAULT_HEIGHT', description: 'the default height of the exported chart. Used when no value is set.' }, defaultWidth: { value: 600, type: 'number', envLink: 'EXPORT_DEFAULT_WIDTH', description: 'The default width of the exported chart. Used when no value is set.' }, defaultScale: { value: 1, type: 'number', envLink: 'EXPORT_DEFAULT_SCALE', description: 'The default scale of the exported chart. Used when no value is set.' }, height: { value: false, type: 'number', description: 'The height of the exported chart, overriding the option in the chart settings.' }, width: { value: false, type: 'number', description: 'The width of the exported chart, overriding the option in the chart settings.' }, scale: { value: false, type: 'number', description: 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.' }, globalOptions: { value: false, type: 'string', description: 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.' }, themeOptions: { value: false, type: 'string', description: 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.' }, batch: { value: false, type: 'string', description: 'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".' }, rasterizationTimeout: { value: 1500, type: 'number', envLink: 'EXPORT_RASTERIZATION_TIMEOUT', description: 'The duration in milliseconds to wait for rendering a webpage.' } }, customLogic: { allowCodeExecution: { value: false, type: 'boolean', envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION', description: 'Controls whether the execution of arbitrary code is allowed during the exporting process.' }, allowFileResources: { value: false, type: 'boolean', envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES', description: 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.' }, customCode: { value: false, type: 'string', description: 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.' }, callback: { value: false, type: 'string', description: 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.' }, resources: { value: false, type: 'string', description: 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.' }, loadConfig: { value: false, type: 'string', legacyName: 'fromFile', description: 'A file containing a pre-defined configuration to use.' }, createConfig: { value: false, type: 'string', description: 'Enables setting options through a prompt and saving them in a provided config file.' } }, server: { enable: { value: false, type: 'boolean', envLink: 'SERVER_ENABLE', cliName: 'enableServer', description: 'When set to true, the server starts on the local IP address 0.0.0.0.' }, host: { value: '0.0.0.0', type: 'string', envLink: 'SERVER_HOST', description: 'The hostname of the server. Additionally, it starts a server on the provided hostname.' }, port: { value: 7801, type: 'number', envLink: 'SERVER_PORT', description: 'The server port when enabled.' }, benchmarking: { value: false, type: 'boolean', envLink: 'SERVER_BENCHMARKING', cliName: 'serverBenchmarking', description: 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.' }, proxy: { host: { value: false, type: 'string', envLink: 'SERVER_PROXY_HOST', cliName: 'proxyHost', description: 'The host of the proxy server to use, if it exists.' }, port: { value: 8080, type: 'number', envLink: 'SERVER_PROXY_PORT', cliName: 'proxyPort', description: 'The port of the proxy server to use, if it exists.' }, timeout: { value: 5000, type: 'number', envLink: 'SERVER_PROXY_TIMEOUT', cliName: 'proxyTimeout', description: 'The timeout for the proxy server to use, if it exists.' } }, rateLimiting: { enable: { value: false, type: 'boolean', envLink: 'SERVER_RATE_LIMITING_ENABLE', cliName: 'enableRateLimiting', description: 'Enables rate limiting for the server.' }, maxRequests: { value: 10, type: 'number', envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS', legacyName: 'rateLimit', description: 'The maximum number of requests allowed in one minute.' }, window: { value: 1, type: 'number', envLink: 'SERVER_RATE_LIMITING_WINDOW', description: 'The time window, in minutes, for the rate limiting.' }, delay: { value: 0, type: 'number', envLink: 'SERVER_RATE_LIMITING_DELAY', description: 'The delay duration for each successive request before reaching the maximum limit.' }, trustProxy: { value: false, type: 'boolean', envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY', description: 'Set this to true if the server is behind a load balancer.' }, skipKey: { value: false, type: 'string', envLink: 'SERVER_RATE_LIMITING_SKIP_KEY', description: 'Allows bypassing the rate limiter and should be provided with the skipToken argument.' }, skipToken: { value: false, type: 'string', envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN', description: 'Allows bypassing the rate limiter and should be provided with the skipKey argument.' } }, ssl: { enable: { value: false, type: 'boolean', envLink: 'SERVER_SSL_ENABLE', cliName: 'enableSsl', description: 'Enables or disables the SSL protocol.' }, force: { value: false, type: 'boolean', envLink: 'SERVER_SSL_FORCE', cliName: 'sslForce', legacyName: 'sslOnly', description: 'When set to true, the server is forced to serve only over HTTPS.' }, port: { value: 443, type: 'number', envLink: 'SERVER_SSL_PORT', cliName: 'sslPort', description: 'The port on which to run the SSL server.' }, certPath: { value: false, type: 'string', envLink: 'SERVER_SSL_CERT_PATH', legacyName: 'sslPath', description: 'The path to the SSL certificate/key file.' } } }, pool: { minWorkers: { value: 4, type: 'number', envLink: 'POOL_MIN_WORKERS', description: 'The number of minimum and initial pool workers to spawn.' }, maxWorkers: { value: 8, type: 'number', envLink: 'POOL_MAX_WORKERS', legacyName: 'workers', description: 'The number of maximum pool workers to spawn.' }, workLimit: { value: 40, type: 'number', envLink: 'POOL_WORK_LIMIT', description: 'The number of work pieces that can be performed before restarting the worker process.' }, acquireTimeout: { value: 5000, type: 'number', envLink: 'POOL_ACQUIRE_TIMEOUT', description: 'The duration, in milliseconds, to wait for acquiring a resource.' }, createTimeout: { value: 5000, type: 'number', envLink: 'POOL_CREATE_TIMEOUT', description: 'The duration, in milliseconds, to wait for creating a resource.' }, destroyTimeout: { value: 5000, type: 'number', envLink: 'POOL_DESTROY_TIMEOUT', description: 'The duration, in milliseconds, to wait for destroying a resource.' }, idleTimeout: { value: 30000, type: 'number', envLink: 'POOL_IDLE_TIMEOUT', description: 'The duration, in milliseconds, after which an idle resource is destroyed.' }, createRetryInterval: { value: 200, type: 'number', envLink: 'POOL_CREATE_RETRY_INTERVAL', description: 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.' }, reaperInterval: { value: 1000, type: 'number', envLink: 'POOL_REAPER_INTERVAL', description: 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.' }, benchmarking: { value: false, type: 'boolean', envLink: 'POOL_BENCHMARKING', cliName: 'poolBenchmarking', description: 'Indicate whether to show statistics for the pool of resources or not.' } }, logging: { level: { value: 4, type: 'number', envLink: 'LOGGING_LEVEL', cliName: 'logLevel', description: 'The logging level to be used.' }, file: { value: 'highcharts-export-server.log', type: 'string', envLink: 'LOGGING_FILE', cliName: 'logFile', description: 'The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging.' }, dest: { value: 'log/', type: 'string', envLink: 'LOGGING_DEST', cliName: 'logDest', description: 'The path to store log files. The `logToFile` option also needs to be set to enable file logging.' }, toConsole: { value: true, type: 'boolean', envLink: 'LOGGING_TO_CONSOLE', cliName: 'logToConsole', description: 'Enables or disables showing logs in the console.' }, toFile: { value: true, type: 'boolean', envLink: 'LOGGING_TO_FILE', cliName: 'logToFile', description: 'Enables or disables creation of the log directory and saving the log into a .log file.' } }, ui: { enable: { value: false, type: 'boolean', envLink: 'UI_ENABLE', cliName: 'enableUi', description: 'Enables or disables the user interface (UI) for the export server.' }, route: { value: '/', type: 'string', envLink: 'UI_ROUTE', cliName: 'uiRoute', description: 'The endpoint route to which the user interface (UI) should be attached.' } }, other: { nodeEnv: { value: 'production', type: 'string', envLink: 'OTHER_NODE_ENV', description: 'The type of Node.js environment.' }, listenToProcessExits: { value: true, type: 'boolean', envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS', description: 'Decides whether or not to attach process.exit handlers.' }, noLogo: { value: false, type: 'boolean', envLink: 'OTHER_NO_LOGO', description: 'Skip printing the logo on a startup. Will be replaced by a simple text.' }, hardResetPage: { value: false, type: 'boolean', envLink: 'OTHER_HARD_RESET_PAGE', description: 'Decides if the page content should be reset entirely.' }, browserShellMode: { value: true, type: 'boolean', envLink: 'OTHER_BROWSER_SHELL_MODE', description: 'Decides if the browser runs in the shell mode.' } }, debug: { enable: { value: false, type: 'boolean', envLink: 'DEBUG_ENABLE', cliName: 'enableDebug', description: 'Enables or disables debug mode for the underlying browser.' }, headless: { value: true, type: 'boolean', envLink: 'DEBUG_HEADLESS', description: 'Controls the mode in which the browser is launched when in the debug mode.' }, devtools: { value: false, type: 'boolean', envLink: 'DEBUG_DEVTOOLS', description: 'Decides whether to enable DevTools when the browser is in a headful state.' }, listenToConsole: { value: false, type: 'boolean', envLink: 'DEBUG_LISTEN_TO_CONSOLE', description: 'Decides whether to enable a listener for console messages sent from the browser.' }, dumpio: { value: false, type: 'boolean', envLink: 'DEBUG_DUMPIO', description: 'Redirects browser process stdout and stderr to process.stdout and process.stderr.' }, slowMo: { value: 0, type: 'number', envLink: 'DEBUG_SLOW_MO', description: 'Slows down Puppeteer operations by the specified number of milliseconds.' }, debuggingPort: { value: 9222, type: 'number', envLink: 'DEBUG_DEBUGGING_PORT', description: 'Specifies the debugging port.' } } }; // The config descriptions object for the prompts functionality. It contains // information like: // * Type of a prompt // * Name of an option // * Short description of a chosen option // * Initial value export const promptsConfig = { puppeteer: [ { type: 'list', name: 'args', message: 'Puppeteer arguments', initial: defaultConfig.puppeteer.args.value.join(','), separator: ',' } ], highcharts: [ { type: 'text', name: 'version', message: 'Highcharts version', initial: defaultConfig.highcharts.version.value }, { type: 'text', name: 'cdnURL', message: 'The URL of CDN', initial: defaultConfig.highcharts.cdnURL.value }, { type: 'multiselect', name: 'coreScripts', message: 'Available core scripts', instructions: 'Space: Select specific, A: Select all, Enter: Confirm.', choices: defaultConfig.highcharts.coreScripts.value }, { type: 'multiselect', name: 'moduleScripts', message: 'Available module scripts', instructions: 'Space: Select specific, A: Select all, Enter: Confirm.', choices: defaultConfig.highcharts.moduleScripts.value }, { type: 'multiselect', name: 'indicatorScripts', message: 'Available indicator scripts', instructions: 'Space: Select specific, A: Select all, Enter: Confirm.', choices: defaultConfig.highcharts.indicatorScripts.value }, { type: 'list', name: 'customScripts', message: 'Custom scripts', initial: defaultConfig.highcharts.customScripts.value.join(','), separator: ',' }, { type: 'toggle', name: 'forceFetch', message: 'Force re-fetch the scripts', initial: defaultConfig.highcharts.forceFetch.value }, { type: 'text', name: 'cachePath', message: 'The path to the cache directory', initial: defaultConfig.highcharts.cachePath.value } ], export: [ { type: 'select', name: 'type', message: 'The default export file type', hint: `Default: ${defaultConfig.export.type.value}`, initial: 0, choices: ['png', 'jpeg', 'pdf', 'svg'] }, { type: 'select', name: 'constr', message: 'The default constructor for Highcharts', hint: `Default: ${defaultConfig.export.constr.value}`, initial: 0, choices: ['chart', 'stockChart', 'mapChart', 'ganttChart'] }, { type: 'number', name: 'defaultHeight', message: 'The default fallback height of the exported chart', initial: defaultConfig.export.defaultHeight.value }, { type: 'number', name: 'defaultWidth', message: 'The default fallback width of the exported chart', initial: defaultConfig.export.defaultWidth.value }, { type: 'number', name: 'defaultScale', message: 'The default fallback scale of the exported chart', initial: defaultConfig.export.defaultScale.value, min: 0.1, max: 5 }, { type: 'number', name: 'rasterizationTimeout', message: 'The rendering webpage timeout in milliseconds', initial: defaultConfig.export.rasterizationTimeout.value } ], customLogic: [ { type: 'toggle', name: 'allowCodeExecution', message: 'Enable execution of custom code', initial: defaultConfig.customLogic.allowCodeExecution.value }, { type: 'toggle', name: 'allowFileResources', message: 'Enable file resources', initial: defaultConfig.customLogic.allowFileResources.value } ], server: [ { type: 'toggle', name: 'enable', message: 'Starts the server on 0.0.0.0', initial: defaultConfig.server.enable.value }, { type: 'text', name: 'host', message: 'Server hostname', initial: defaultConfig.server.host.value }, { type: 'number', name: 'port', message: 'Server port', initial: defaultConfig.server.port.value }, { type: 'toggle', name: 'benchmarking', message: 'Enable server benchmarking', initial: defaultConfig.server.benchmarking.value }, { type: 'text', name: 'proxy.host', message: 'The host of the proxy server to use', initial: defaultConfig.server.proxy.host.value }, { type: 'number', name: 'proxy.port', message: 'The port of the proxy server to use', initial: defaultConfig.server.proxy.port.value }, { type: 'number', name: 'proxy.timeout', message: 'The timeout for the proxy server to use', initial: defaultConfig.server.proxy.timeout.value }, { type: 'toggle', name: 'rateLimiting.enable', message: 'Enable rate limiting', initial: defaultConfig.server.rateLimiting.enable.value }, { type: 'number', name: 'rateLimiting.maxRequests', message: 'The maximum requests allowed per minute', initial: defaultConfig.server.rateLimiting.maxRequests.value }, { type: 'number', name: 'rateLimiting.window', message: 'The rate-limiting time window in minutes', initial: defaultConfig.server.rateLimiting.window.value }, { type: 'number', name: 'rateLimiting.delay', message: 'The delay for each successive request before reaching the maximum', initial: defaultConfig.server.rateLimiting.delay.value }, { type: 'toggle', name: 'rateLimiting.trustProxy', message: 'Set to true if behind a load balancer', initial: defaultConfig.server.rateLimiting.trustProxy.value }, { type: 'text', name: 'rateLimiting.skipKey', message: 'Allows bypassing the rate limiter when provided with the skipToken argument', initial: defaultConfig.server.rateLimiting.skipKey.value }, { type: 'text', name: 'rateLimiting.skipToken', message: 'Allows bypassing the rate limiter when provided with the skipKey argument', initial: defaultConfig.server.rateLimiting.skipToken.value }, { type: 'toggle', name: 'ssl.enable', message: 'Enable SSL protocol', initial: defaultConfig.server.ssl.enable.value }, { type: 'toggle', name: 'ssl.force', message: 'Force serving only over HTTPS', initial: defaultConfig.server.ssl.force.value }, { type: 'number', name: 'ssl.port', message: 'SSL server port', initial: defaultConfig.server.ssl.port.value }, { type: 'text', name: 'ssl.certPath', message: 'The path to find the SSL certificate/key', initial: defaultConfig.server.ssl.certPath.value } ], pool: [ { type: 'number', name: 'minWorkers', message: 'The initial number of workers to spawn', initial: defaultConfig.pool.minWorkers.value }, { type: 'number', name: 'maxWorkers', message: 'The maximum number of workers to spawn', initial: defaultConfig.pool.maxWorkers.value }, { type: 'number', name: 'workLimit', message: 'The pieces of work that can be performed before restarting a Puppeteer process', initial: defaultConfig.pool.workLimit.value }, { type: 'number', name: 'acquireTimeout', message: 'The number of milliseconds to wait for acquiring a resource', initial: defaultConfig.pool.acquireTimeout.value }, { type: 'number', name: 'createTimeout', message: 'The number of milliseconds to wait for creating a resource', initial: defaultConfig.pool.createTimeout.value }, { type: 'number', name: 'destroyTimeout', message: 'The number of milliseconds to wait for destroying a resource', initial: defaultConfig.pool.destroyTimeout.value }, { type: 'number', name: 'idleTimeout', message: 'The number of milliseconds after an idle resource is destroyed', initial: defaultConfig.pool.idleTimeout.value }, { type: 'number', name: 'createRetryInterval', message: 'The retry interval in milliseconds after a create process fails', initial: defaultConfig.pool.createRetryInterval.value }, { type: 'number', name: 'reaperInterval', message: 'The reaper interval in milliseconds after triggering the check for idle resources to destroy', initial: defaultConfig.pool.reaperInterval.value }, { type: 'toggle', name: 'benchmarking', message: 'Enable benchmarking for a resource pool', initial: defaultConfig.pool.benchmarking.value } ], logging: [ { type: 'number', name: 'level', message: 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)', initial: defaultConfig.logging.level.value, round: 0, min: 0, max: 5 }, { type: 'text', name: 'file', message: 'A log file name. Set with --toFile and --logDest to enable file logging', initial: defaultConfig.logging.file.value }, { type: 'text', name: 'dest', message: 'The path to a log file when the file logging is enabled', initial: defaultConfig.logging.dest.value }, { type: 'toggle', name: 'toConsole', message: 'Enable logging to the console', initial: defaultConfig.logging.toConsole.value }, { type: 'toggle', name: 'toFile', message: 'Enables logging to a file', initial: defaultConfig.logging.toFile.value } ], ui: [ { type: 'toggle', name: 'enable', message: 'Enable UI for the export server', initial: defaultConfig.ui.enable.value }, { type: 'text', name: 'route', message: 'A route to attach the UI', initial: defaultConfig.ui.route.value } ], other: [ { type: 'text', name: 'nodeEnv', message: 'The type of Node.js environment', initial: defaultConfig.other.nodeEnv.value }, { type: 'toggle', name: 'listenToProcessExits', message: 'Set to false to skip attaching process.exit handlers', initial: defaultConfig.other.listenToProcessExits.value }, { type: 'toggle', name: 'noLogo', message: 'Skip printing the logo on startup. Replaced by simple text', initial: defaultConfig.other.noLogo.value }, { type: 'toggle', name: 'hardResetPage', message: 'Decides if the page content should be reset entirely', initial: defaultConfig.other.hardResetPage.value }, { type: 'toggle', name: 'browserShellMode', message: 'Decides if the browser runs in the shell mode', initial: defaultConfig.other.browserShellMode.value } ], debug: [ { type: 'toggle', name: 'enable', message: 'Enables debug mode for the browser instance', initial: defaultConfig.debug.enable.value }, { type: 'toggle', name: 'headless', message: 'The mode setting for the browser', initial: defaultConfig.debug.headless.value }, { type: 'toggle', name: 'devtools', message: 'The DevTools for the headful browser', initial: defaultConfig.debug.devtools.value }, { type: 'toggle', name: 'listenToConsole', message: 'The event listener for console messages from the browser', initial: defaultConfig.debug.listenToConsole.value }, { type: 'toggle', name: 'dumpio', message: 'Redirects the browser stdout and stderr to NodeJS process', initial: defaultConfig.debug.dumpio.value }, { type: 'number', name: 'slowMo', message: 'Puppeteer operations slow down in milliseconds', initial: defaultConfig.debug.slowMo.value }, { type: 'number', name: 'debuggingPort', message: 'The port number for debugging', initial: defaultConfig.debug.debuggingPort.value } ] }; // Absolute props that, in case of merging recursively, need to be force merged export const absoluteProps = [ 'options', 'globalOptions', 'themeOptions', 'resources', 'payload' ]; // Argument nesting level of all export server options export const nestedArgs = {}; /** * Recursively creates a chain of nested arguments from an object. * * @param {Object} obj - The object containing nested arguments. * @param {string} propChain - The current chain of nested properties * (used internally during recursion). */ const createNestedArgs = (obj, propChain = '') => { Object.keys(obj).forEach((k) => { if (!['puppeteer', 'highcharts'].includes(k)) { const entry = obj[k]; if (typeof entry.value === 'undefined') { // Go deeper in the nested arguments createNestedArgs(entry, `${propChain}.${k}`); } else { // Create the chain of nested arguments nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1); // Support for the legacy, PhantomJS properties names if (entry.legacyName !== undefined) { nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1); } } } }); }; createNestedArgs(defaultConfig);