flagpole
Version:
Simple and fast DOM integration, headless or headful browser, and REST API testing framework.
280 lines • 10.4 kB
JavaScript
;
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