UNPKG

@appsemble/lang-sdk

Version:

Language SDK for Appsemble

174 lines 6.85 kB
import { Validator, } from 'jsonschema'; import { schemas as allSchemas } from './index.js'; import { escapeJsonPointer } from './jsonPointer.js'; import { has } from './miscellaneous.js'; export class BaseValidatorFactory { constructor({ customFormats, schemas }) { this.customFormats = customFormats; this.schemas = schemas; } build() { const validator = new Validator(); for (const [key, format] of Object.entries(this.customFormats ?? {})) { validator.customFormats[key] = format; } for (const [key, schema] of Object.entries(this.schemas)) { const path = `#/components/schemas/${escapeJsonPointer(key)}`; validator.addSchema(schema, path); } return validator; } } BaseValidatorFactory.defaultOptions = { base: '#', nestedErrors: true, }; BaseValidatorFactory.defaultCustomFormats = { int32: () => true, int64: () => true, float: () => true, double: () => true, byte: () => true, binary: () => true, password: () => true, }; export class BlockExampleValidator { constructor() { this.validator = new BaseValidatorFactory({ schemas: allSchemas, customFormats: { ...BaseValidatorFactory.defaultCustomFormats, fontawesome: () => true, remapper: () => true, action: () => true, 'event-listener': () => true, 'event-emitter': () => true, }, }).build(); } validate(example) { const { required, ...blockSchema } = structuredClone(allSchemas.BlockDefinition); delete blockSchema.properties?.name; delete blockSchema.properties?.version; const actionsSchema = blockSchema.properties.actions; delete actionsSchema?.additionalProperties; if (example.actions) { actionsSchema.properties = Object.fromEntries(Object.keys(example.actions).map((key) => [ key, { $ref: '#/components/schemas/ActionDefinition' }, ])); } const blockEventsSchema = { type: 'object', additionalProperties: false, properties: {}, }; blockSchema.properties.events = blockEventsSchema; if (example.events) { if (example.events.emit) { blockEventsSchema.properties.emit = has(example.events.emit, '$any') ? { type: 'object', additionalProperties: { type: 'string' } } : { type: 'object', properties: Object.fromEntries(Object.keys(example.events.emit).map((emitter) => [emitter, { type: 'string' }])), }; } if (example.events.listen) { blockEventsSchema.properties.listen = has(example.events.listen, '$any') ? { type: 'object', additionalProperties: { type: 'string' } } : { type: 'object', properties: Object.fromEntries(Object.keys(example.events.listen).map((listener) => [ listener, { type: 'string' }, ])), }; } } const validationResult = this.validator.validate(example, blockSchema, BaseValidatorFactory.defaultOptions); return validationResult; } } export class BlockParamInstanceValidator { constructor({ actions = [], emitters = [], listeners = [], } = {}) { this.emitterNames = []; this.listenerNames = []; this.emitterNames = emitters; this.listenerNames = listeners; this.validator = new BaseValidatorFactory({ schemas: {}, customFormats: { ...BaseValidatorFactory.defaultCustomFormats, // TODO: validate more fontawesome: () => true, // TODO: validate more remapper: () => true, action: (property) => actions.includes(property), 'event-listener': (property) => listeners.includes(property), 'event-emitter': (property) => emitters.includes(property), }, }).build(); } validateParametersInstance(instance, schema) { const actionFormat = this.validator.customFormats.action; const listenerFormat = this.validator.customFormats['event-listener']; const emitterFormat = this.validator.customFormats['event-emitter']; const actionsReferenced = new Set(); this.validator.customFormats.action = (property) => { actionsReferenced.add(property); return actionFormat(property); }; this.validator.customFormats['event-listener'] = (property) => listenerFormat(property) && this.listenerNames.includes(property); this.validator.customFormats['event-emitter'] = (property) => emitterFormat(property) && this.emitterNames.includes(property); const result = this.validator.validate(instance, schema, { ...BaseValidatorFactory.defaultOptions, base: undefined, }); return [result, actionsReferenced]; } } export class BlockParamSchemaValidator { constructor() { this.validator = new BaseValidatorFactory({ schemas: allSchemas, customFormats: { ...BaseValidatorFactory.defaultCustomFormats, fontawesome: () => true, remapper: () => true, action: () => true, 'event-listener': () => true, 'event-emitter': () => true, }, }).build(); } validateParamSchema(paramSchema) { return this.validator.validate(paramSchema, allSchemas.JSONSchemaRoot, BaseValidatorFactory.defaultOptions); } } export class AppValidator { constructor() { this.validator = new BaseValidatorFactory({ schemas: allSchemas, customFormats: { ...BaseValidatorFactory.defaultCustomFormats, }, }).build(); } validateApp(app) { return this.validator.validate(app, allSchemas.AppDefinition, BaseValidatorFactory.defaultOptions); } } export class RemapperValidator { constructor() { this.validator = new BaseValidatorFactory({ schemas: allSchemas, customFormats: { ...BaseValidatorFactory.defaultCustomFormats, }, }).build(); } validateRemapper(remapper) { return this.validator.validate(remapper, allSchemas.RemapperDefinition, BaseValidatorFactory.defaultOptions); } } //# sourceMappingURL=BasicValidator.js.map