import { ABILITY_VERSION_JSON_NAME, DEFAULT_ABILITY_PACKAGE_NAME } from '@/constants' import type { ModuleTypeKey, ConstraintContext, LocalAbilityItem, ConstraintValidator, } from '@/types' import { MODULE_TYPE } from '@ones-open/utils' import { createRequire } from 'module' import { abilityValidators } from './ability-validators' import { moduleValidators } from './module-validators' const require = createRequire(import.meta.url) const abilityConfigList: LocalAbilityItem[] = require( `${DEFAULT_ABILITY_PACKAGE_NAME}/${ABILITY_VERSION_JSON_NAME}`, ) const abilityConfigMap: Record = abilityConfigList.reduce( (result, current) => { return { ...result, [`${current.ability_type}@${current.ability_version}`]: current, } }, {}, ) const getAbilityConstraints = (abilityType: string): Record => { const constraints = { ...(abilityConfigMap?.[abilityType]?.constraints || {}), } return constraints } const getModuleConstraints = (moduleType: string): Record => { const baseConstraints = { iconFormat: /\.svg$/i, } const constraints = { ...baseConstraints, ...(MODULE_TYPE[moduleType as ModuleTypeKey]?.constraints || {}), } as Record // if both the constraint rule 'maxNum' and 'localMaxNum' exist, skip 'maxNum' if (constraints.localMaxNum && constraints.maxNum) { Reflect.deleteProperty(constraints, 'maxNum') } return constraints } const createValidateConstraintsFunc = ( getConstraints: (type: string) => Record, validators: Record, ) => async (type: string, baseContext: Pick) => { const constraints = getConstraints(type) const validationPromises = Object.entries(constraints) .filter(([rule]) => !!validators[rule]) .map(([rule, arg]) => { return validators[rule](arg)({ ...baseContext, type, }) }) const results = await Promise.allSettled(validationPromises) const errorMsgs = results .filter(({ status }) => status === 'rejected') .map((result) => { const { reason } = result as PromiseRejectedResult return `[${type}] ${typeof reason === 'string' ? reason : reason.message}` }) if (errorMsgs.length > 0) { throw errorMsgs.join('\n') } return type } interface ResultInfo { name: string disabled?: string } const createBatchValidateConstraintsFunc = (checkConstraints: ReturnType) => async ( types: string[], baseContext: Pick, ): Promise<[ResultInfo[], string]> => { const allvalidationResults = await Promise.allSettled( types.map((type) => checkConstraints(type, baseContext)), ) const allErrorMsgs: string[] = [] const allResultsInfo: ResultInfo[] = [] allvalidationResults.forEach((result, i) => { const moduleInfo: ResultInfo = { name: types[i] } if (result.status != 'fulfilled') { allErrorMsgs.push(result.reason) moduleInfo.disabled = result.reason } allResultsInfo.push(moduleInfo) }) return [allResultsInfo, allErrorMsgs.join('\n')] } const validateModuleConstraints = createValidateConstraintsFunc( getModuleConstraints, moduleValidators, ) const validateAbilityConstraints = createValidateConstraintsFunc( getAbilityConstraints, abilityValidators, ) const batchValidateModuleConstraints = createBatchValidateConstraintsFunc(validateModuleConstraints) const batchValidateAbilityConstraints = createBatchValidateConstraintsFunc( validateAbilityConstraints, ) export { batchValidateModuleConstraints, batchValidateAbilityConstraints, validateModuleConstraints, validateAbilityConstraints, }