UNPKG

@pega/custom-dx-components

Version:

Utility for building custom UI components

385 lines (354 loc) 12.1 kB
import path from 'path'; import fs from 'fs'; import chalk from 'chalk'; import inquirer from 'inquirer'; import Ajv from 'ajv'; import { COMPONENT_SCHEMA } from '../../constants.js'; import { getComponentDirectoryPath, getComponents, getOOTBComponents, addDebugLog } from '../../util.js'; const ajv = new Ajv({ allErrors: true }); const combinationTypes = ['PAGE', 'CASE']; const allowedSubtypes = [ ...new Set([ ...COMPONENT_SCHEMA.subtype.field.map(({ value }) => value), ...COMPONENT_SCHEMA.subtype.template.map(({ value }) => value), ...COMPONENT_SCHEMA.subtype.widget.map(({ value }) => value) ]) ]; // additional subtypes are manually added below const allowedOverrideSubtypes = [ ...new Set([ ...COMPONENT_SCHEMA.subtype.field.map(({ value }) => value), ...COMPONENT_SCHEMA.subtype.template.map(({ value }) => value), ...COMPONENT_SCHEMA.subtype.widget.map(({ value }) => value) ]), "ACTION", "DATA_CAPTURE", "SUMMARY", "CASEVIEW", "DATAVIEW", "LIST" ]; const schema = { type: 'object', properties: { baseComponentName: { type: 'string' }, componentKey: { type: 'string', pattern: '^[A-Za-z0-9]+_[A-Za-z0-9]+_[A-Za-z0-9]+$' }, name: { type: 'string', pattern: '^[A-Za-z0-9]+_[A-Za-z0-9]+_[A-Za-z0-9]+$' }, label: { type: 'string' }, description: { type: 'string' }, organization: { type: 'string' }, version: { type: 'string' }, library: { type: 'string' }, allowedApplications: { type: 'array' }, type: { type: 'string', enum: COMPONENT_SCHEMA.type.map(({ value }) => value) }, subtype: { anyOf: [{ type: 'string' }, { type: 'array' }], enum: allowedSubtypes }, icon: { type: 'string' }, properties: { type: 'array', uniqueItems: true, items: { anyOf: [ { type: 'object', properties: { name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['name', 'label', 'format'] }, { type: 'object', properties: { format: { type: 'string' }, source: { type: 'object', properties: { name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['name', 'label', 'format'] }, cascadeElements: { type: 'array', uniqueItems: true, items: { anyOf: [ { type: 'object', properties: { key: { type: 'string'}, name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['key','name', 'label', 'format'] } ] } }, }, required: ['format'] }, { type: 'object', properties: { label: { type: 'string' }, format: { type: 'string' }, properties: { type: 'array', uniqueItems: true, items: { anyOf: [ { type: 'object', properties: { name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['name', 'label', 'format'] }, { type: 'object', properties: { variant: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['variant', 'label', 'format'] }, { type: 'object', properties: { format: { type: 'string' }, elements: { type: 'array', uniqueItems: true, items: { anyOf: [ { type: 'object', properties: { key: { type: 'string' }, name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' }, variant: { type: 'string' } }, required: ['key', 'format', 'label'] } ] } } }, required: ['format', 'elements'] }, ] } } }, required: ['label', 'format'], } ] } }, defaultConfig: { type: 'object' } }, required: ['componentKey', 'name', 'description', 'type', 'subtype', 'properties'], additionalProperties: true }; const overrideSchema = { type: 'object', properties: { baseComponentName: { type: 'string' }, componentKey: { type: 'string', pattern: '^[A-Za-z0-9]+$' }, name: { type: 'string', pattern: '^[A-Za-z0-9]+$' }, label: { type: 'string' }, description: { type: 'string' }, organization: { type: 'string' }, version: { type: 'string' }, library: { type: 'string' }, allowedApplications: { type: 'array' }, type: { type: 'string', enum: COMPONENT_SCHEMA.type.map(({ value }) => value) }, subtype: { anyOf: [{ type: 'string' }, { type: 'array' }], enum: allowedOverrideSubtypes }, icon: { type: 'string' }, properties: { type: 'array', uniqueItems: true, items: { anyOf: [ { type: 'object', properties: { name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['name', 'label', 'format'] }, { type: 'object', properties: { format: { type: 'string' }, source: { type: 'object', properties: { name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['name', 'label', 'format'] }, cascadeElements: { type: 'array', uniqueItems: true, items: { anyOf: [ { type: 'object', properties: { key: { type: 'string'}, name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['key','name', 'label', 'format'] } ] } }, }, required: ['format'] }, { type: 'object', properties: { label: { type: 'string' }, format: { type: 'string' }, properties: { type: 'array', uniqueItems: true, items: { anyOf: [ { type: 'object', properties: { name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['name', 'label', 'format'] }, { type: 'object', properties: { variant: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' } }, required: ['variant', 'label', 'format'] }, { type: 'object', properties: { format: { type: 'string' }, elements: { type: 'array', uniqueItems: true, items: { anyOf: [ { type: 'object', properties: { key: { type: 'string' }, name: { type: 'string' }, label: { type: 'string' }, format: { type: 'string' }, variant: { type: 'string' } }, required: ['key', 'format', 'label'] } ] } } }, required: ['format', 'elements'] }, ] } } }, required: ['label', 'format'], } ] } }, defaultConfig: { type: 'object' } }, required: ['name', 'type', 'subtype', 'properties', 'componentKey'], additionalProperties: true }; const validateSchema = ajv.compile(schema); const validateOverideSchema = ajv.compile(overrideSchema); export default async (option) => { // addDebugLog("validate","", ""); let componentToValidate = null; if (option.params && option.params[3]) { componentToValidate = option.params[3]; } else if (option && option.task === 'validateSchema') { const localComponents = await getComponents(); const answer = await inquirer.prompt({ name: 'component', type: 'rawlist', message: 'Select component to validate', choices: localComponents }); componentToValidate = answer.component; } else if (option.name) { componentToValidate = option.value; } else { componentToValidate = option; } const componentDirectory = await getComponentDirectoryPath(componentToValidate); let configFileName = "config.json"; const configFile = path.join(componentDirectory, configFileName); let configData; try { configData = fs.readFileSync(path.resolve(configFile), 'utf8'); } catch (err) { // for now, if now file just end console.log(`${chalk.bold.yellow('Config file not availabe for: ' + componentToValidate)}`); return; } //const data = JSON.parse(fs.readFileSync(path.resolve(configFile), 'utf8')); let data; try { data = JSON.parse(configData); } catch (er) { throw new Error(`Invalid schema json in config.json: ${er}`); } const valid = validateSchema(data); if (valid) { if ( componentToValidate && !/^[A-Za-z0-9]+_[A-Za-z0-9]+_[A-Za-z0-9]+$/.test(componentToValidate) ) { const ootbComponents = await getOOTBComponents(); if (ootbComponents.includes(componentToValidate)) { throw new Error(`Invalid: Error occurred in validating ${componentToValidate}`); } } console.log(`${chalk.bold.green(componentToValidate)} schema is valid`); } else { throw new Error(`Invalid: ${ajv.errorsText(validateSchema.errors)}`); } };