vue-data-ui-cli
Version:
A CLI tool to generate Vue Data UI chart component boilerplates
637 lines (618 loc) • 17.4 kB
JavaScript
#!/usr/bin/env node
import { program } from 'commander';
import { existsSync, mkdirSync, writeFileSync } from 'fs';
import { resolve, join } from 'path';
import chalk from 'chalk';
import prettier from 'prettier';
import boilerplate from './boilerplate.js';
import inquirer from 'inquirer';
import datasets from './datasets.js';
import emitExamples from './emits.js'
let getVueDataUiConfig;
try {
({ getVueDataUiConfig } = await import('vue-data-ui'));
} catch (err) {
console.error(
chalk.red('Failed to load vue-data-ui. Please ensure it is installed.')
);
process.exit(1);
}
const supportedComponents = {
VueUiChord: {
key: 'vue_ui_chord',
link: 'vue-ui-chord',
datasetType: 'VueUiChordDataset',
configType: 'VueUiChordConfig',
isDatasetArray: false,
slots: ['source']
},
VueUiRidgeline: {
key: 'vue_ui_ridgeline',
link: 'vue-ui-ridgeline',
datasetType: 'VueUiRidgelineDatasetItem',
configType: 'VueUiRidgelineConfig',
isDatasetArray: true,
slots: ['source']
},
VueUiWorld: {
key: 'vue_ui_world',
link: 'vue-ui-world',
datasetType: 'VueUiWorldDataset',
configType: 'VueUiWorldConfig',
isDatasetArray: false,
slots: ['source']
},
VueUiXy: {
key: 'vue_ui_xy',
link: 'vue-ui-xy',
datasetType: 'VueUiXyDatasetItem',
configType: 'VueUiXyConfig',
isDatasetArray: true,
slots: [
'svg',
'legend',
'tooltip-before',
'tooltip-after',
'reset-action',
'time-label',
'watermark',
'source',
'plot-comment',
],
},
VueUiDonut: {
key: 'vue_ui_donut',
link: 'vue-ui-donut',
datasetType: 'VueUiDonutDatasetItem',
isDatasetArray: true,
configType: 'VueUiDonutConfig',
slots: ['source']
},
VueUiNestedDonuts: {
key: 'vue_ui_nested_donuts',
link: 'vue-ui-nested-donuts',
datasetType: 'VueUiNestedDonutsDatasetItem',
isDatasetArray: true,
configType: 'VueUiNestedDonutsConfig',
slots: ['source']
},
VueUiQuickChart: {
key: 'vue_ui_quick_chart',
link: 'vue-ui-quick-chart',
datasetType: 'VueUiQuickChartDataset',
isDatasetArray: false,
configType: 'VueUiQuickChartConfig',
slots: ['source']
},
VueUiStackbar: {
key: 'vue_ui_stackbar',
link: 'vue-ui-stackbar',
datasetType: 'VueUiStackbarDatasetItem',
isDatasetArray: true,
configType: 'VueUiStackbarConfig',
slots: ['source']
},
VueUiSparkline: {
key: 'vue_ui_sparkline',
link: 'vue-ui-sparkline',
datasetType: 'VueUiSparklineDatasetItem',
isDatasetArray: true,
configType: 'VueUiSparklineConfig',
slots: ['source']
},
VueUiSparkbar: {
key: 'vue_ui_sparkbar',
link: 'vue-ui-sparkbar',
datasetType: 'VueUiSparkbarDatasetItem',
isDatasetArray: true,
configType: 'VueUiSparkbarConfig',
slots: ['source']
},
VueUiSparkStackbar: {
key:'vue_ui_sparkstackbar',
link: 'vue-ui-sparkstackbar',
datasetType: 'VueUiSparkStackbarDatasetItem',
isDatasetArray: true,
configType: 'VueUiSparkStackbarConfig',
slots: ['source']
},
VueUiGauge: {
key: 'vue_ui_gauge',
link: 'vue-ui-gauge',
datasetType: 'VueUiGaugeDataset',
isDatasetArray: false,
configType: 'VueUiGaugeConfig',
slots: ['source']
},
VueUiSparkHistogram: {
key: 'vue_ui_sparkhistogram',
link: 'vue-ui-sparkhistogram',
datasetType: 'VueUiSparkHistogramDatasetItem',
isDatasetArray: true,
configType: 'VueUiSparkHistogramConfig',
slots: ['source']
},
VueUiSparkgauge: {
key: 'vue_ui_sparkgauge',
link: 'vue-ui-sparkgauge',
datasetType: 'VueUiSparkgaugeDataset',
isDatasetArray: false,
configType: 'VueUiSparkgaugeConfig',
slots: ['source']
},
VueUiSparkTrend: {
key: 'vue_ui_spark_trend',
link: 'vueè-ui-spark-trend',
datasetType: 'number',
isDatasetArray: true,
configType: 'VueUiSparkTrendConfig',
slots: ['source']
},
VueUiGizmo: {
key: 'vue_ui_gizmo',
link: 'vue-ui-gizmo',
datasetType: 'number',
isDatasetArray: false,
configType: 'VueUiGizmoConfig',
slots: []
},
VueUiKpi: {
key: 'vue_ui_kpi',
link: 'vue-ui-kpi',
datasetType: 'number',
isDatasetArray: false,
configType: 'VueUiKpiConfig',
slots: []
},
VueUiBullet: {
key: 'vue_ui_bullet',
link: 'vue-ui-bullet',
datasetType: 'VueUiBulletDataset',
isDatasetArray: false,
configType: 'VueUiBulletConfig',
slots: ['source']
},
VueUiXyCanvas: {
key: 'vue_ui_xy_canvas',
link: 'vue-ui-xy-canvas',
datasetType: 'VueUiXyCanvasDatasetItem',
isDatasetArray: true,
configType: 'VueUiXyCanvasConfig',
slots: ['source']
},
VueUiHorizontalBar: {
key: 'vue_ui_horizontal_bar',
link: 'vue-ui-horizontal-bar',
datasetType: 'VueUiHorizontalBarDatasetItem',
isDatasetArray: true,
configType: 'VueUiHorizontalBarConfig',
slots: ['source']
},
VueUiParallelCoordinatePlot: {
key: 'vue_ui_parallel_coordinate_plot',
link: 'vue-ui-parallel-coordinate-plot',
datasetType: 'VueUiParallelCoordinatePlotDatasetItem',
isDatasetArray: true,
configType: 'VueUiParallelCoordinatePlotConfig',
slots: ['source']
},
VueUiFlow: {
key: 'vue_ui_flow',
link: 'vue-ui-flow',
datasetType: 'VueUiFlowDatasetItem',
isDatasetArray: true,
configType: 'VueUiFlowConfig',
slots: ['source']
},
VueUiCandlestick: {
key: 'vue_ui_candlestick',
link: 'vue-ui-candlestick',
datasetType: 'Array<Array<string | number>>',
isDatasetArray: false,
configType: 'VueUiCandlestickConfig',
slots: ['source']
},
VueUiAgePyramid: {
key: 'vue_ui_age_pyramid',
link: 'vue-ui-age-pyramid',
datasetType: 'Array<Array<string | number>>',
isDatasetArray: false,
configType: 'VueUiAgePyramidConfig',
slots: ['source']
},
VueUiDonutEvolution: {
key: 'vue_ui_donut_evolution',
link: 'vue-ui-donut-evolution',
datasetType: 'VueUiDonutEvolutionDatasetItem',
isDatasetArray: true,
configType: 'VueUiDonutEvolutionConfig',
slots: ['source']
},
VueUiFunnel: {
key: 'vue_ui_funnel',
link: 'vue-ui-funnel',
datasetType: 'VueUiFunnelDatasetItem',
isDatasetArray: true,
configType: 'VueUiFunnelConfig',
slots: ['source']
},
VueUiHistoryPlot: {
key: 'vue_ui_history_plot',
link: 'vue-ui-history-plot',
datasetType: 'VueUiHistoryPlotDatasetItem',
isDatasetArray: true,
configType: 'VueUiHistoryPlotConfig',
slots: ['source']
},
VueUiWaffle: {
key: 'vue_ui_waffle',
link: 'vue-ui-waffle',
datasetType: 'VueUiWaffleDatasetItem',
isDatasetArray: true,
configType: 'VueUiWaffleConfig',
slots: ['source']
},
VueUiHeatmap: {
key: 'vue_ui_heatmap',
link: 'vue-ui-heatmap',
datasetType: 'VueUiHeatmapDatasetItem',
isDatasetArray: true,
configType: 'VueUiHeatmapConfig',
slots: ['source']
},
VueUiTreemap: {
key: 'vue_ui_treemap',
link: 'vue-ui-treemap',
datasetType: 'VueUiTreemapDatasetItem',
isDatasetArray: true,
configType: 'VueUiTreemapConfig',
slots: ['source']
},
VueUiRings: {
key: 'vue_ui_rings',
link: 'vue-ui-rings',
datasetType: 'VueUiRingsDatasetItem',
isDatasetArray: true,
configType: 'VueUiRingsConfig',
slots: ['source']
},
VueUiGalaxy: {
key: 'vue_ui_galaxy',
link: 'vue-ui-galaxy',
datasetType: 'VueUiGalaxyDatasetItem',
isDatasetArray: true,
configType: 'VueUiGalaxyConfig',
slots: ['source']
},
VueUiChestnut: {
key: 'vue_ui_chestnut',
link: 'vue-ui-chestnut',
datasetType: 'VueUiChestnutDatasetRoot',
isDatasetArray: true,
configType: 'VueUiChestnutConfig',
slots: ['source']
},
VueUiOnion: {
key: 'vue_ui_onion',
link: 'vue-ui-onion',
datasetType: 'VueUiOnionDatasetItem',
isDatasetArray: true,
configType: 'VueUiOnionConfig',
slots: ['source']
},
VueUiWheel: {
key: 'vue_ui_wheel',
link: 'vue-ui-wheel',
datasetType: 'VueUiWheelDataset',
isDatasetArray: false,
configType: 'VueUiWheelConfig',
slots: ['source']
},
VueUiTiremarks: {
key: 'vue_ui_tiremarks',
link: 'vue-ui-tiremarks',
datasetType: 'VueUiTiremarksDataset',
isDatasetArray: false,
configType: 'VueUiTiremarksConfig',
slots: ['source']
},
VueUiThermometer: {
key: 'vue_ui_thermometer',
link: 'vue-ui-thermometer',
datasetType: 'VueUiThermometerDataset',
isDatasetArray: false,
configType: 'VueUiThermometerConfig',
slots: ['source']
},
VueUiWordCloud: {
key: 'vue_ui_word_cloud',
link: 'vue-ui-word-cloud',
datasetType: 'VueUiWordCloudDatasetItem',
isDatasetArray: true,
configType: 'VueUiWordCloudConfig',
slots: ['source']
},
VueUiRelationCircle: {
key: 'vue_ui_relation_circle',
link: 'vue-ui-relation-circle',
datasetType: 'VueUiRelationCircleDatasetItem',
isDatasetArray: true,
configType: 'VueUiRelationCircleConfig',
slots: ['source']
},
VueUiRadar: {
key: 'vue_ui_radar',
link: 'vue-ui-radar',
datasetType: 'VueUiRadarDataset',
isDatasetArray: false,
configType: 'VueUiRadarConfig',
slots: ['source']
},
VueUiMoodRadar: {
key: 'vue_ui_mood_radar',
link: 'vue-ui-mood-radar',
datasetType: 'VueUiMoodRadarDataset',
isDatasetArray: false,
configType: 'VueUiMoodRadarConfig',
slots: ['source']
},
VueUiQuadrant: {
key: 'vue_ui_quadrant',
link: 'vue-ui-quadrant',
datasetType: 'VueUiQuadrantDatasetItem',
isDatasetArray: true,
configType: 'VueUiQuadrantConfig',
slots: ['source']
},
VueUiScatter: {
key: 'vue_ui_scatter',
link: 'vue-ui-scatter',
datasetType: 'VueUiScatterDatasetItem',
isDatasetArray: true,
configType: 'VueUiScatterConfig',
slots: ['source']
},
VueUiMolecule: {
key: 'vue_ui_molecule',
link: 'vue-ui-molecule',
datasetType: 'VueUiMoleculeDatasetNode',
isDatasetArray: true,
configType: 'VueUiMoleculeConfig',
slots: ['source']
},
VueUiStripPlot: {
key: 'vue_ui_strip_plot',
link: 'vue-ui-strip-plot',
datasetType: 'VueUiStripPlotDataset',
isDatasetArray: true,
configType: 'VueUiStripPlotConfig',
slots: ['source']
},
VueUiDumbbell: {
key: 'vue_ui_dumbbell',
link: 'vue-ui-dumbbell',
datasetType: 'VueUiDumbbellDataset',
isDatasetArray: true,
configType: 'VueUiDumbbellConfig',
slots: ['source']
},
VueUi3dBar: {
key: 'vue_ui_3d_bar',
link: 'vue-ui-3d-bar',
datasetType: 'VueUi3dBarDataset',
isDatasetArray: false,
configType: 'VueUi3dBarConfig',
slots: ['source']
},
VueUiTableSparkline: {
key: 'vue_ui_table_sparkline',
link: 'vue-ui-table-sparkline',
datasetType: 'VueUiTableSparklineDatasetItem',
isDatasetArray: true,
configType: 'VueUiTableSparklineConfig',
slots: ['source']
},
VueUiCarouselTable: {
key: 'vue_ui_carousel_table',
link: 'vue-ui-carousel-table',
datasetType: 'VueUiCarouselTableDataset',
isDatasetArray: false,
configType: 'VueUiCarouselTableConfig',
slots: ['source']
},
VueUiRating: {
key: 'vue_ui_rating',
link: 'vue-ui-rating',
datasetType: 'VueUiRatingDataset',
isDatasetArray: false,
configType: 'VueUiRatingConfig',
slots: []
},
VueUiSmiley: {
key: 'vue_ui_smiley',
link: 'vue-ui-smiley',
datasetType: 'VueUiRatingDataset',
isDatasetArray: false,
configType: 'VueUiSmileyConfig',
slots: []
},
VueUiAccordion: {
key: 'vue_ui_accordion',
link: 'vue-ui-accordion',
datasetType: '',
isDatasetArray: false,
configType: 'VueUiAccordionConfig',
slots: ['content']
},
VueUiSkeleton: {
key: 'vue_ui_skeleton',
link: 'vue-ui-skeleton',
datasetType: '',
isDatasetArray: false,
configType: 'VueUiSkeletonConfig',
slots: []
},
VueUiCirclePack: {
key: 'vue_ui_circle_pack',
link: 'vue-ui-circle-pack',
datasetType: 'VueUiCirclePackDatasetItem',
isDatasetArray: true,
configType: 'VueUiCirclePackConfig',
slots: ['source']
},
};
(function displayBanner() {
console.log(chalk.green.bold(`
▗▖ ▗▖▗▖ ▗▖▗▄▄▄▖ ▗▄▄▄ ▗▄▖▗▄▄▄▖▗▄▖ ▗▖ ▗▖ ▄ ▗▄▄▖▗▖ ▄
▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌ █▐▌ ▐▌ █ ▐▌ ▐▌ ▐▌ ▐▌ █ ▐▌ ▐▌
▐▌ ▐▌▐▌ ▐▌▐▛▀▀▘ ▐▌ █▐▛▀▜▌ █ ▐▛▀▜▌ ▐▌ ▐▌ █ ▐▌ ▐▌ █
▝▚▞▘ ▝▚▄▞▘▐▙▄▄▖ ▐▙▄▄▀▐▌ ▐▌ █ ▐▌ ▐▌ ▝▚▄▞▘ █ ▝▚▄▄▖▐▙▄▄▖ █
`))
console.log(chalk.blue.bold(`Create Vue Data UI boilerplate components easily\n\n`))
})()
program
.version('3.0.2')
.description('CLI to generate Vue Data UI component boilerplates')
.action(async () => {
const answers = await inquirer.prompt([
{
type: 'list',
name: 'chartComponent',
message: 'Select a Vue Data UI chart component:\n',
choices: Object.keys(supportedComponents),
validate: (input) =>
input ? true : 'You must select a chart component.',
},
{
type: 'confirm',
name: 'useComputedDataset',
message: 'Use computed for the dataset ? (Answering no will use ref)',
default: false,
},
{
type: 'confirm',
name: 'useComputedConfig',
message: 'Use computed for the config ? (Answering no will use ref)',
default: false,
},
{
type: 'confirm',
name: 'useTypescript',
message: 'Would you like to use TypeScript?',
default: false,
},
{
type: 'input',
name: 'componentName',
message: 'Enter the name of your Vue component (e.g., MyComponent):',
validate: (input) => (input ? true : 'Component name is required.'),
},
{
type: 'input',
name: 'directory',
message: 'Enter the directory to create the component in:',
default: './src/components/charts',
},
]);
const {
componentName,
chartComponent,
useTypescript,
directory,
useComputedDataset,
useComputedConfig,
} = answers;
const targetDir = resolve(directory);
const fileName = `${componentName}.vue`;
const filePath = join(targetDir, fileName);
if (!existsSync(targetDir)) {
mkdirSync(targetDir, { recursive: true });
}
const componentKey = supportedComponents[chartComponent].key;
if (!componentKey) {
console.error(
chalk.red(`${chartComponent} is not a valid Vue Data UI component.`)
);
process.exit(1);
}
let config;
try {
config = await getVueDataUiConfig(componentKey);
} catch (err) {
console.error(
chalk.red(`Failed to get configuration for ${chartComponent}.`)
);
process.exit(1);
}
let dataset;
try {
dataset = datasets(chartComponent);
} catch (err) {
console.error(
chalk.red(`Failed to get dataset boilerplate for ${chartComponent}.`)
);
process.exit(1);
}
let emits;
try {
emits = emitExamples(chartComponent);
} catch (err) {
console.error(
chalk.red(`Failed to get emits for ${chartComponent}.`)
);
process.exit(1);
}
let rawContent;
try {
rawContent = boilerplate({
component: chartComponent,
config,
dataset,
useTypescript,
useComputedConfig,
useComputedDataset,
datasetType: supportedComponents[chartComponent].datasetType,
configType: supportedComponents[chartComponent].configType,
isDatasetArray: supportedComponents[chartComponent].isDatasetArray,
componentSlots: supportedComponents[chartComponent].slots,
componentLink: supportedComponents[chartComponent].link,
emits
});
if (typeof rawContent !== 'string') {
console.error(chalk.red('Boilerplate content is not a valid string.'));
process.exit(1);
}
} catch (err) {
console.error(chalk.red('Error generating boilerplate content.'));
process.exit(1);
}
// Prettier formatting
let formattedContent;
try {
const prettierOptions = (await prettier.resolveConfig(process.cwd())) || {
parser: 'vue',
};
formattedContent = await prettier.format(rawContent, prettierOptions);
} catch (err) {
console.warn(
chalk.yellow('Prettier formatting failed. Writing unformatted content.')
);
formattedContent = rawContent;
}
if (typeof formattedContent !== 'string') {
console.error(chalk.red('Formatted content is not a valid string.'));
process.exit(1);
}
try {
writeFileSync(filePath, formattedContent);
console.log(
chalk.green(
`Component ${fileName} created and formatted at ${filePath}`
)
);
} catch (err) {
console.error(chalk.red('Error writing to file:'), err);
process.exit(1);
}
});
program.parse(process.argv);