UNPKG

flagpole

Version:

Simple and fast DOM integration, headless or headful browser, and REST API testing framework.

280 lines 10.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.AssertionSchema = exports.SchemaValidator = exports.generateAjvSchema = exports.writeSchema = exports.getSchema = exports.getSchemaPath = void 0; const util_1 = require("./util"); const flagpoleexecution_1 = require("./flagpoleexecution"); const fs_extra_1 = require("fs-extra"); const path_1 = require("path"); function getSchemaPath(schemaName) { let path; if (schemaName.startsWith("@") && schemaName.length > 1) { const schemasFolder = flagpoleexecution_1.FlagpoleExecution.global.config.getSchemasFolder(); if (!schemasFolder) { throw "Flagpole schema folder path not found."; } fs_extra_1.ensureDirSync(schemasFolder); path = path_1.resolve(schemasFolder, `${schemaName.substr(1)}.json`); } else { path = path_1.resolve(schemaName); } fs_extra_1.ensureFileSync(path); return path; } exports.getSchemaPath = getSchemaPath; function getSchema(schemaName) { const schemaPath = getSchemaPath(schemaName); if (fs_extra_1.existsSync(schemaPath)) { const content = fs_extra_1.readFileSync(schemaPath, "utf8"); return JSON.parse(content); } throw `Schema file ${schemaPath} does not exist`; } exports.getSchema = getSchema; function writeSchema(json, schemaName) { const schema = generateAjvSchema(json); fs_extra_1.writeFileSync(getSchemaPath(schemaName), JSON.stringify(schema, null, 2)); return schema; } exports.writeSchema = writeSchema; function generateAjvSchema(json) { const ajvTypes = [ "string", "number", "integer", "boolean", "array", "object", "null", ]; function parseObject(obj) { const schema = { type: ["object"], properties: {}, }; Object.keys(obj).forEach((key) => { if (schema.properties) { schema.properties[key] = parseItem(obj[key]); } }); return schema; } function parseArray(arr) { const schema = { type: ["array"], }; if (arr.length > 0) { const containsAllObjects = arr.every((row) => util_1.toType(row) === "object"); if (containsAllObjects) { schema.items = { type: ["object"], properties: {}, }; arr.forEach((row) => { const rowSchema = parseItem(row); if (rowSchema.properties) { Object.keys(rowSchema.properties).forEach((key) => { if (!schema.items || !schema.items.properties || !rowSchema.properties) { return; } const prevItem = schema.items.properties[key]; const newItem = rowSchema.properties[key]; if (!prevItem) { schema.items.properties[key] = newItem; } else { const newType = Array.isArray(newItem.type) ? newItem.type : [newItem.type]; const prevType = Array.isArray(prevItem.type) ? prevItem.type : [prevItem.type]; schema.items.properties[key].type = util_1.arrayUnique([ ...prevType, ...newType, ]); } }); } }); } else { schema.items = { type: util_1.arrayUnique(arr.map((value) => util_1.toType(value))), }; } } return schema; } function parseItem(item) { const myType = util_1.toType(item); if (myType === "object") { return parseObject(item); } else if (myType == "array") { return parseArray(item); } else { return { type: [myType], }; } } return parseItem(json); } exports.generateAjvSchema = generateAjvSchema; class SchemaValidator { constructor(schema) { this._schema = typeof schema === "string" ? getSchema(schema) : generateAjvSchema(schema); } isValid(item) { const assertion = new AssertionSchema(); return assertion.isValid(this._schema, item); } } exports.SchemaValidator = SchemaValidator; class AssertionSchema { constructor() { this._errors = []; } get errors() { return this._errors; } isValid(schema, root) { this._errors = []; return this._isValid(schema, root, "$"); } validate(schema, root) { return __awaiter(this, void 0, void 0, function* () { return this.isValid(schema, root); }); } _logError(message) { const err = new Error(message); this._errors.push(err); } _matchesType(schema, document, path) { const schemaType = util_1.toType(schema); const docType = util_1.toType(document); if (schemaType != "undefined") { if (schemaType == "string") { if (docType != schema) { this._logError(`typeOf ${path} was ${docType}, which did not match ${schema}`); return false; } } else if (schemaType == "array") { const allowedTypes = schema; if (allowedTypes.indexOf(docType) < 0) { this._logError(`${path} was ${docType}, which did not match ${allowedTypes.join(" | ")}`); return false; } } } return true; } _matchesEnum(schema, document, path) { if (util_1.toType(schema) == "array") { if (schema.indexOf(document) < 0) { this._logError(`${path} value ${document} is not in enum ${schema.join(", ")}`); return false; } } return true; } _matchesPattern(schema, document, path) { const schemaType = util_1.toType(schema); if (schemaType != "undefined" && !new RegExp(schema).test(String(document))) { this._logError(`${path} value ${document} did not match ${String(schema)}`); return false; } return true; } _matchesItems(schema, document, path) { const schemaType = util_1.toType(schema); const docType = util_1.toType(document); if (schemaType != "undefined") { if (docType != "array") { this._logError(`${path} was not an array, but schema defines items.`); return false; } return document.every((subItem, index) => { if (schemaType == "string" || schemaType == "array") { return this._matchesType(schema, subItem, `${path}[${index}]`); } else if (schemaType == "object") { return this._isValid(schema, subItem, `${path}[${index}]`); } return true; }); } return true; } _matchesProperties(schema, document, path) { const schemaType = util_1.toType(schema); const docType = util_1.toType(document); if (schemaType != "undefined") { if (docType != "object") { this._logError(`${path} was not an object, but schema defines properties.`); return false; } if (schemaType == "string" || schemaType == "array") { return Object.keys(document).every((key) => { return this._matchesType(schema, document[key], `${path}.${key}`); }); } if (schemaType == "object") { return Object.keys(schema).every((key) => { return this._isValid(schema[key], document[key], `${path}.${key}`); }); } } return true; } _isValid(schema, document, path) { const schemaType = util_1.toType(schema); const docType = util_1.toType(document); if (schemaType == "string" || schemaType == "array") { if (!this._matchesType(schema, document, path)) { return false; } } else if (schemaType == "object") { if (!this._matchesType(schema.type, document, path)) { if (!schema.optional || typeof document != "undefined") { return false; } } if (!this._matchesEnum(schema.enum, document, path)) { return false; } if (!this._matchesPattern(schema.matches, document, path)) { return false; } if (!this._matchesItems(schema.items, document, path)) { return false; } if (!this._matchesProperties(schema.properties, document, path)) { return false; } } return true; } } exports.AssertionSchema = AssertionSchema; //# sourceMappingURL=assertionschema.js.map