webextensions-api-mock
Version:
WebExtensions API as sinon stubs
260 lines (259 loc) • 9.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var SchemaType;
(function (SchemaType) {
SchemaType[SchemaType["Namespace"] = 1] = "Namespace";
SchemaType[SchemaType["Type"] = 2] = "Type";
SchemaType[SchemaType["ObjectProperty"] = 3] = "ObjectProperty";
})(SchemaType = exports.SchemaType || (exports.SchemaType = {}));
/**
Identifies either a NamespaceSchema or TypeSchema, and helps
create schemaIds for references to other TypeSchemas.
*/
class SchemaId {
constructor(name, type) {
this.name = name;
this.type = type;
}
get namespace() {
if (this.type === SchemaType.Namespace) {
return this.name;
}
else {
return this.name.substring(0, this.name.lastIndexOf('.'));
}
}
get namespaceId() {
return this.type === SchemaType.Namespace
? this
: new SchemaId(this.namespace, SchemaType.Namespace);
}
toString() {
return `${SchemaType[this.type]}::${this.name}`;
}
withRef(refName) {
const name = refName.includes('.')
? refName
: `${this.namespace}.${refName}`;
return new SchemaId(name, SchemaType.Type);
}
withObjectProperty(propertyName) {
const suffix = propertyName || '{object}';
const name = `${this.name}::${suffix}`;
return new SchemaId(name, SchemaType.ObjectProperty);
}
static withNamespace(namespace) {
return new SchemaId(namespace.namespace, SchemaType.Namespace);
}
static withType(name) {
return new SchemaId(name, SchemaType.Type);
}
}
exports.SchemaId = SchemaId;
var SchemaWalkerFlags;
(function (SchemaWalkerFlags) {
SchemaWalkerFlags[SchemaWalkerFlags["None"] = 0] = "None";
SchemaWalkerFlags[SchemaWalkerFlags["SuppressWarnings"] = 2] = "SuppressWarnings";
SchemaWalkerFlags[SchemaWalkerFlags["NoTypeValueReuse"] = 4] = "NoTypeValueReuse";
})(SchemaWalkerFlags = exports.SchemaWalkerFlags || (exports.SchemaWalkerFlags = {}));
class SchemaWalker {
constructor(delegate, flags) {
this.types = new Map();
this.outs = new Map();
this.delegate = delegate;
this.flags = flags || SchemaWalkerFlags.None;
}
walk(schemaNamespaces) {
this.extractTypes(schemaNamespaces);
this.extractNamespaces(schemaNamespaces);
}
extractTypes(schemaNamespaces) {
Object.values(schemaNamespaces).forEach(namespaces => namespaces.forEach(namespace => {
if (!namespace.types) {
return;
}
namespace.types.forEach(type => {
if (!type.id)
return;
const typeId = type.id.includes('.')
? type.id
: `${namespace.namespace}.${type.id}`;
this.types.set(typeId, { typeschema: type });
});
}));
this.types.forEach((value, key) => {
this.schema(SchemaId.withType(key), value.typeschema);
});
}
extractNamespaces(schemaNamespaces) {
Object.values(schemaNamespaces).forEach(namespaces => namespaces.forEach(namespace => this.schema(SchemaId.withNamespace(namespace), namespace)));
}
schema(schemaId, schema, out) {
if (schema.$import) {
this.delegate.handleImport(schemaId, schema.$import, out);
return undefined;
}
switch (schemaId.type) {
case SchemaType.Namespace: // Fall through
case SchemaType.ObjectProperty:
return this.namespaceOrObjectProperty(schemaId, schema, out);
case SchemaType.Type:
return this.type(schemaId, schema);
}
}
namespaceOrObjectProperty(schemaId, schema, out) {
let node;
if (schemaId.type === SchemaType.Namespace) {
node = this.outs.get(schemaId.name);
if (!node) {
node = this.delegate.createNamespaceValue(schemaId, out);
this.outs.set(schemaId.name, node);
}
}
else {
node = this.delegate.startObjectPropertyValue(schemaId, out);
}
if (!node)
return;
if (schema.properties) {
Object.keys(schema.properties).forEach(propertyName => {
if (!schema.properties)
return;
const property = schema.properties[propertyName];
const optional = property.optional || property.unsupported;
const value = this.value(schemaId, property, node, propertyName);
this.field(schemaId, propertyName, value, !!optional, node);
});
}
if (schema.functions) {
schema.functions.forEach(fn => {
if (!fn.name || fn.type !== 'function') {
return;
}
const optional = fn.optional || fn.unsupported;
const value = this.fn(schemaId, fn, node);
this.field(schemaId, fn.name, value, !!optional, node);
});
}
if (schema.events) {
schema.events.forEach(event => {
if (!event.name || event.type !== 'function') {
return;
}
const value = this.event(schemaId, node);
this.field(schemaId, event.name, value, false, node);
});
}
if (schemaId.type === SchemaType.ObjectProperty) {
const newNode = this.delegate.finishObjectPropertyValue(schemaId, node);
if (newNode)
node = newNode;
}
return node;
}
field(schemaId, name, value, optional, out) {
if (value === undefined) {
return;
}
this.delegate.handleField(schemaId, name, value, optional, out);
}
type(schemaId, schema) {
let node = this.outs.get(schemaId.name);
if (!node || this.flags & SchemaWalkerFlags.NoTypeValueReuse) {
// Circular-reference check
const type = this.types.get(schemaId.name);
if (type) {
if (type.locked) {
return this.delegate.valueForCircularType(schemaId);
}
else {
type.locked = true;
}
}
// Create namespace if needed
let out = this.outs.get(schemaId.namespace);
if (!out) {
out = this.schema(schemaId.namespaceId, {});
}
// Create type value
node = this.value(schemaId, schema, out);
if (node) {
const newNode = this.delegate.finishTypeValue(schemaId, node, out);
if (newNode)
node = newNode;
this.outs.set(schemaId.name, node);
}
if (type)
type.locked = false;
}
return node;
}
value(schemaId, schema, out, name) {
if (schema.value) {
return schema.value;
}
else if (schema.$ref) {
return this.ref(schemaId.withRef(schema.$ref));
}
else if (schema.enum) {
const enums = schema.enum.map(enumObj => {
return typeof enumObj === 'object' ? enumObj.name : enumObj;
});
return this.delegate.createEnumValue(schemaId, schema.type || 'string', enums, out);
}
else if (schema.type) {
switch (schema.type) {
case 'string': // Fall through
case 'boolean': // Fall through
case 'integer': // Fall through
case 'number': // Fall through
case 'any': // Fall through
case 'choices': // Fall through
return this.delegate.createPlainValue(schemaId, schema.type, false, out);
case 'array':
const items = schema.items;
if (items) {
const arrayType = this.value(schemaId, items, out, name) || 'any';
return this.delegate.createPlainValue(schemaId, arrayType, true, out);
}
else {
return undefined;
}
case 'function':
return this.fn(schemaId, schema, out);
case 'event':
return this.event(schemaId, out);
case 'object':
return this.schema(schemaId.withObjectProperty(name), schema, out);
}
}
else if (schema.choices) {
return this.delegate.createPlainValue(schemaId, 'choices', false, out);
}
}
event(schemaId, out) {
return this.delegate.createEventValue(schemaId, out);
}
fn(schemaId, schema, out) {
let returnValue = undefined;
if (schema.returns && schema.returns.$ref) {
returnValue = this.ref(schemaId.withRef(schema.returns.$ref));
}
return this.delegate.createFnValue(schemaId, returnValue, out);
}
ref(schemaId) {
var _a, _b, _c;
const schema = (_a = this.types.get(schemaId.name)) === null || _a === void 0 ? void 0 : _a.typeschema;
if (schema) {
return this.schema(schemaId, schema);
}
else {
if (((_c = (_b = process) === null || _b === void 0 ? void 0 : _b.env) === null || _c === void 0 ? void 0 : _c.NODE_ENV) !== 'production' &&
!(this.flags & SchemaWalkerFlags.SuppressWarnings)) {
console.warn(`Ref not found '${schemaId.name}'`);
}
return this.delegate.valueForInvalidRef(schemaId);
}
}
}
exports.SchemaWalker = SchemaWalker;