@polytric/openws-spec 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +399 -71
- package/dist/builder.cjs +380 -0
- package/dist/builder.cjs.map +1 -0
- package/dist/builder.d.cts +77 -0
- package/dist/builder.d.ts +77 -0
- package/dist/builder.js +347 -0
- package/dist/builder.js.map +1 -0
- package/dist/chunk-7D4SUZUM.js +38 -0
- package/dist/chunk-7D4SUZUM.js.map +1 -0
- package/dist/index.cjs +1110 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +139 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +1074 -0
- package/dist/index.js.map +1 -0
- package/dist/types.cjs +19 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +42 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -14
- package/index.js +0 -11
- package/spec.js +0 -62
- package/spec.json +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// ../node_modules/.pnpm/rfdc@1.4.1/node_modules/rfdc/index.js
|
|
34
|
+
var require_rfdc = __commonJS({
|
|
35
|
+
"../node_modules/.pnpm/rfdc@1.4.1/node_modules/rfdc/index.js"(exports2, module2) {
|
|
36
|
+
"use strict";
|
|
37
|
+
module2.exports = rfdc;
|
|
38
|
+
function copyBuffer(cur) {
|
|
39
|
+
if (cur instanceof Buffer) {
|
|
40
|
+
return Buffer.from(cur);
|
|
41
|
+
}
|
|
42
|
+
return new cur.constructor(cur.buffer.slice(), cur.byteOffset, cur.length);
|
|
43
|
+
}
|
|
44
|
+
function rfdc(opts) {
|
|
45
|
+
opts = opts || {};
|
|
46
|
+
if (opts.circles) return rfdcCircles(opts);
|
|
47
|
+
const constructorHandlers = /* @__PURE__ */ new Map();
|
|
48
|
+
constructorHandlers.set(Date, (o) => new Date(o));
|
|
49
|
+
constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)));
|
|
50
|
+
constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)));
|
|
51
|
+
if (opts.constructorHandlers) {
|
|
52
|
+
for (const handler2 of opts.constructorHandlers) {
|
|
53
|
+
constructorHandlers.set(handler2[0], handler2[1]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let handler = null;
|
|
57
|
+
return opts.proto ? cloneProto : clone;
|
|
58
|
+
function cloneArray(a, fn) {
|
|
59
|
+
const keys = Object.keys(a);
|
|
60
|
+
const a2 = new Array(keys.length);
|
|
61
|
+
for (let i = 0; i < keys.length; i++) {
|
|
62
|
+
const k = keys[i];
|
|
63
|
+
const cur = a[k];
|
|
64
|
+
if (typeof cur !== "object" || cur === null) {
|
|
65
|
+
a2[k] = cur;
|
|
66
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
67
|
+
a2[k] = handler(cur, fn);
|
|
68
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
69
|
+
a2[k] = copyBuffer(cur);
|
|
70
|
+
} else {
|
|
71
|
+
a2[k] = fn(cur);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return a2;
|
|
75
|
+
}
|
|
76
|
+
function clone(o) {
|
|
77
|
+
if (typeof o !== "object" || o === null) return o;
|
|
78
|
+
if (Array.isArray(o)) return cloneArray(o, clone);
|
|
79
|
+
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
|
80
|
+
return handler(o, clone);
|
|
81
|
+
}
|
|
82
|
+
const o2 = {};
|
|
83
|
+
for (const k in o) {
|
|
84
|
+
if (Object.hasOwnProperty.call(o, k) === false) continue;
|
|
85
|
+
const cur = o[k];
|
|
86
|
+
if (typeof cur !== "object" || cur === null) {
|
|
87
|
+
o2[k] = cur;
|
|
88
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
89
|
+
o2[k] = handler(cur, clone);
|
|
90
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
91
|
+
o2[k] = copyBuffer(cur);
|
|
92
|
+
} else {
|
|
93
|
+
o2[k] = clone(cur);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return o2;
|
|
97
|
+
}
|
|
98
|
+
function cloneProto(o) {
|
|
99
|
+
if (typeof o !== "object" || o === null) return o;
|
|
100
|
+
if (Array.isArray(o)) return cloneArray(o, cloneProto);
|
|
101
|
+
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
|
102
|
+
return handler(o, cloneProto);
|
|
103
|
+
}
|
|
104
|
+
const o2 = {};
|
|
105
|
+
for (const k in o) {
|
|
106
|
+
const cur = o[k];
|
|
107
|
+
if (typeof cur !== "object" || cur === null) {
|
|
108
|
+
o2[k] = cur;
|
|
109
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
110
|
+
o2[k] = handler(cur, cloneProto);
|
|
111
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
112
|
+
o2[k] = copyBuffer(cur);
|
|
113
|
+
} else {
|
|
114
|
+
o2[k] = cloneProto(cur);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return o2;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function rfdcCircles(opts) {
|
|
121
|
+
const refs = [];
|
|
122
|
+
const refsNew = [];
|
|
123
|
+
const constructorHandlers = /* @__PURE__ */ new Map();
|
|
124
|
+
constructorHandlers.set(Date, (o) => new Date(o));
|
|
125
|
+
constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn)));
|
|
126
|
+
constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn)));
|
|
127
|
+
if (opts.constructorHandlers) {
|
|
128
|
+
for (const handler2 of opts.constructorHandlers) {
|
|
129
|
+
constructorHandlers.set(handler2[0], handler2[1]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
let handler = null;
|
|
133
|
+
return opts.proto ? cloneProto : clone;
|
|
134
|
+
function cloneArray(a, fn) {
|
|
135
|
+
const keys = Object.keys(a);
|
|
136
|
+
const a2 = new Array(keys.length);
|
|
137
|
+
for (let i = 0; i < keys.length; i++) {
|
|
138
|
+
const k = keys[i];
|
|
139
|
+
const cur = a[k];
|
|
140
|
+
if (typeof cur !== "object" || cur === null) {
|
|
141
|
+
a2[k] = cur;
|
|
142
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
143
|
+
a2[k] = handler(cur, fn);
|
|
144
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
145
|
+
a2[k] = copyBuffer(cur);
|
|
146
|
+
} else {
|
|
147
|
+
const index = refs.indexOf(cur);
|
|
148
|
+
if (index !== -1) {
|
|
149
|
+
a2[k] = refsNew[index];
|
|
150
|
+
} else {
|
|
151
|
+
a2[k] = fn(cur);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return a2;
|
|
156
|
+
}
|
|
157
|
+
function clone(o) {
|
|
158
|
+
if (typeof o !== "object" || o === null) return o;
|
|
159
|
+
if (Array.isArray(o)) return cloneArray(o, clone);
|
|
160
|
+
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
|
161
|
+
return handler(o, clone);
|
|
162
|
+
}
|
|
163
|
+
const o2 = {};
|
|
164
|
+
refs.push(o);
|
|
165
|
+
refsNew.push(o2);
|
|
166
|
+
for (const k in o) {
|
|
167
|
+
if (Object.hasOwnProperty.call(o, k) === false) continue;
|
|
168
|
+
const cur = o[k];
|
|
169
|
+
if (typeof cur !== "object" || cur === null) {
|
|
170
|
+
o2[k] = cur;
|
|
171
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
172
|
+
o2[k] = handler(cur, clone);
|
|
173
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
174
|
+
o2[k] = copyBuffer(cur);
|
|
175
|
+
} else {
|
|
176
|
+
const i = refs.indexOf(cur);
|
|
177
|
+
if (i !== -1) {
|
|
178
|
+
o2[k] = refsNew[i];
|
|
179
|
+
} else {
|
|
180
|
+
o2[k] = clone(cur);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
refs.pop();
|
|
185
|
+
refsNew.pop();
|
|
186
|
+
return o2;
|
|
187
|
+
}
|
|
188
|
+
function cloneProto(o) {
|
|
189
|
+
if (typeof o !== "object" || o === null) return o;
|
|
190
|
+
if (Array.isArray(o)) return cloneArray(o, cloneProto);
|
|
191
|
+
if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) {
|
|
192
|
+
return handler(o, cloneProto);
|
|
193
|
+
}
|
|
194
|
+
const o2 = {};
|
|
195
|
+
refs.push(o);
|
|
196
|
+
refsNew.push(o2);
|
|
197
|
+
for (const k in o) {
|
|
198
|
+
const cur = o[k];
|
|
199
|
+
if (typeof cur !== "object" || cur === null) {
|
|
200
|
+
o2[k] = cur;
|
|
201
|
+
} else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) {
|
|
202
|
+
o2[k] = handler(cur, cloneProto);
|
|
203
|
+
} else if (ArrayBuffer.isView(cur)) {
|
|
204
|
+
o2[k] = copyBuffer(cur);
|
|
205
|
+
} else {
|
|
206
|
+
const i = refs.indexOf(cur);
|
|
207
|
+
if (i !== -1) {
|
|
208
|
+
o2[k] = refsNew[i];
|
|
209
|
+
} else {
|
|
210
|
+
o2[k] = cloneProto(cur);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
refs.pop();
|
|
215
|
+
refsNew.pop();
|
|
216
|
+
return o2;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// ../node_modules/.pnpm/@pocketgems+schema@0.1.3/node_modules/@pocketgems/schema/src/schema.js
|
|
223
|
+
var require_schema = __commonJS({
|
|
224
|
+
"../node_modules/.pnpm/@pocketgems+schema@0.1.3/node_modules/@pocketgems/schema/src/schema.js"(exports2, module2) {
|
|
225
|
+
"use strict";
|
|
226
|
+
var assert = require("assert");
|
|
227
|
+
var ajv;
|
|
228
|
+
var deepcopy = require_rfdc()();
|
|
229
|
+
var ValidationError = class extends Error {
|
|
230
|
+
/**
|
|
231
|
+
* @param {string} name a user-provided name describing the schema
|
|
232
|
+
* @param {*} badValue the value which did not validate
|
|
233
|
+
* @param {Object} errors how badValue failed to conform to the schema
|
|
234
|
+
* @param {Object} expectedSchema The JSON schema used in schema validation
|
|
235
|
+
*/
|
|
236
|
+
constructor(name, badValue, errors, expectedSchema) {
|
|
237
|
+
super(`Validation Error: ${name}`);
|
|
238
|
+
this.badValue = badValue;
|
|
239
|
+
this.validationErrors = errors;
|
|
240
|
+
this.expectedSchema = expectedSchema;
|
|
241
|
+
if (["localhost", "webpack"].includes(process.env.NODE_ENV)) {
|
|
242
|
+
console.error(JSON.stringify(errors, null, 2));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
var INT32_MAX = Math.pow(2, 31) - 1;
|
|
247
|
+
var INT32_MIN = -Math.pow(2, 31);
|
|
248
|
+
var TIMESTAMP_MIN = "2000-01-01T00:00:00Z";
|
|
249
|
+
var TIMESTAMP_MAX = "9999-01-01T00:00:00Z";
|
|
250
|
+
var EPOCH_IN_MILLISECONDS_MIN = new Date(TIMESTAMP_MIN).getTime();
|
|
251
|
+
var EPOCH_IN_MILLISECONDS_MAX = new Date(TIMESTAMP_MAX).getTime();
|
|
252
|
+
var EPOCH_IN_SECONDS_MIN = EPOCH_IN_MILLISECONDS_MIN / 1e3;
|
|
253
|
+
var EPOCH_IN_SECONDS_MAX = EPOCH_IN_MILLISECONDS_MAX / 1e3;
|
|
254
|
+
var INT64_MAX = Math.pow(2, 62);
|
|
255
|
+
var INT64_MIN = -Math.pow(2, 62);
|
|
256
|
+
var BaseSchema = class {
|
|
257
|
+
/**
|
|
258
|
+
* The json schema type
|
|
259
|
+
*/
|
|
260
|
+
static JSON_SCHEMA_TYPE;
|
|
261
|
+
/**
|
|
262
|
+
* The max* property name.
|
|
263
|
+
*/
|
|
264
|
+
static MAX_PROP_NAME;
|
|
265
|
+
/**
|
|
266
|
+
* The min* property name.
|
|
267
|
+
*/
|
|
268
|
+
static MIN_PROP_NAME;
|
|
269
|
+
/**
|
|
270
|
+
* Constructs a schema object
|
|
271
|
+
*/
|
|
272
|
+
constructor() {
|
|
273
|
+
this.isTodeaSchema = true;
|
|
274
|
+
this.isFluentSchema = true;
|
|
275
|
+
this.__properties = {};
|
|
276
|
+
this.__isLocked = false;
|
|
277
|
+
this.__isOptional = false;
|
|
278
|
+
this.__setProp("type", this.constructor.JSON_SCHEMA_TYPE);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Locks a Todea Schema object from modifications.
|
|
282
|
+
*/
|
|
283
|
+
lock() {
|
|
284
|
+
this.__isLocked = true;
|
|
285
|
+
return this;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Sets a value in __properties. Throws if object is locked (unless the
|
|
289
|
+
* property is allowed to be overridden), or property with
|
|
290
|
+
* the same name already exists and override is not allowed.
|
|
291
|
+
* @param {String} name Name of the property
|
|
292
|
+
* @param {*} val The value for the property
|
|
293
|
+
* @param {Object} [options={}]
|
|
294
|
+
* @param {Boolean} [options.allowOverride=false] If true property override
|
|
295
|
+
* is allowed.
|
|
296
|
+
*/
|
|
297
|
+
__setProp(name, val, { allowOverride = false } = {}) {
|
|
298
|
+
assert.ok(
|
|
299
|
+
!this.__isLocked || allowOverride,
|
|
300
|
+
"Schema is locked. Call copy then further modify the schema"
|
|
301
|
+
);
|
|
302
|
+
assert.ok(
|
|
303
|
+
allowOverride || !Object.prototype.hasOwnProperty.call(this.__properties, name),
|
|
304
|
+
`Property ${name} is already set.`
|
|
305
|
+
);
|
|
306
|
+
const shouldCopy = this.__isLocked || allowOverride && Object.prototype.hasOwnProperty.call(this.__properties, name);
|
|
307
|
+
const ret = shouldCopy ? this.copy() : this;
|
|
308
|
+
ret.__properties[name] = val;
|
|
309
|
+
if (this.__isLocked) {
|
|
310
|
+
ret.lock();
|
|
311
|
+
}
|
|
312
|
+
return ret;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* @param {String} name Name of a property
|
|
316
|
+
* @return The value associated with name.
|
|
317
|
+
*/
|
|
318
|
+
getProp(name) {
|
|
319
|
+
return this.__properties[name];
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* If property with name does not exist, the default value is set.
|
|
323
|
+
* @param {String} name
|
|
324
|
+
* @param {*} defaultValue
|
|
325
|
+
* @return The value associated with name.
|
|
326
|
+
*/
|
|
327
|
+
__setDefaultProp(name, defaultValue) {
|
|
328
|
+
if (!Object.prototype.hasOwnProperty.call(this.__properties, name)) {
|
|
329
|
+
this.__setProp(name, defaultValue);
|
|
330
|
+
}
|
|
331
|
+
return this.getProp(name);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Sets a title.
|
|
335
|
+
* @param {String} t The title of the schema.
|
|
336
|
+
*/
|
|
337
|
+
title(t) {
|
|
338
|
+
assert.ok(typeof t === "string", "Title must be a string.");
|
|
339
|
+
return this.__setProp("title", t, { allowOverride: true });
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Sets a description.
|
|
343
|
+
* @param {String|Array<String>} t The description of the schema. If an array
|
|
344
|
+
* of strings are passed in, they will be joined by a space to form the
|
|
345
|
+
* description.
|
|
346
|
+
*/
|
|
347
|
+
desc(d) {
|
|
348
|
+
assert.ok(typeof d === "string", "Description must be a string.");
|
|
349
|
+
d = d.trim().replace(/\n/g, " ");
|
|
350
|
+
return this.__setProp("description", d, { allowOverride: true });
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Sets a default value for schema.
|
|
354
|
+
*
|
|
355
|
+
* According to JsonSchema, default value is just metadata and does not
|
|
356
|
+
* serve any validation purpose with in JsonSchema. External tools may
|
|
357
|
+
* choose to use this value to setup defaults, and implementations of
|
|
358
|
+
* JsonSchema validator may choose to validate the type of default values,
|
|
359
|
+
* but it's not required. Since when the default is used to populate the
|
|
360
|
+
* json, there will be something downstream that validates the json and
|
|
361
|
+
* catches issues, we omit schema validation for simplicity.
|
|
362
|
+
*
|
|
363
|
+
* @param {*} d The default value.
|
|
364
|
+
*/
|
|
365
|
+
default(d) {
|
|
366
|
+
assert(d !== void 0, "Default value must be defined");
|
|
367
|
+
Object.freeze(d);
|
|
368
|
+
return this.__setProp("default", d);
|
|
369
|
+
}
|
|
370
|
+
getDefault() {
|
|
371
|
+
return this.properties().default;
|
|
372
|
+
}
|
|
373
|
+
hasDefault() {
|
|
374
|
+
return Object.prototype.hasOwnProperty.call(this.properties(), "default");
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Marks a schema as optional. Schemas are required by default.
|
|
378
|
+
*/
|
|
379
|
+
optional() {
|
|
380
|
+
assert(!this.__isLocked, "Schema is locked.");
|
|
381
|
+
this.__isOptional = true;
|
|
382
|
+
return this;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Convenient getter indicates if the schema is required / not optional.
|
|
386
|
+
* See {@link optional}.
|
|
387
|
+
*/
|
|
388
|
+
get required() {
|
|
389
|
+
return !this.__isOptional;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Sets schemas readOnly property.
|
|
393
|
+
* @param {Boolean} [r=true] If the schema value should be readOnly.
|
|
394
|
+
*/
|
|
395
|
+
readOnly(r = true) {
|
|
396
|
+
return this.__setProp("readOnly", r);
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Updates schemas examples.
|
|
400
|
+
* @param {Array<String|Array<String>>} es A list of examples. Each example
|
|
401
|
+
* may be a string, or a list of strings. In case of a list of strings, the
|
|
402
|
+
* strings will be joined by a space character and used as one example.
|
|
403
|
+
*/
|
|
404
|
+
examples(es) {
|
|
405
|
+
assert.ok(Array.isArray(es), "Examples must be an array");
|
|
406
|
+
es = es.map((e) => {
|
|
407
|
+
return Array.isArray(e) ? e.join(" ") : e;
|
|
408
|
+
});
|
|
409
|
+
return this.__setProp("examples", es, { allowOverride: true });
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Returns a JSON Schema. It exists for compatibility with fluent-schema.
|
|
413
|
+
*/
|
|
414
|
+
valueOf() {
|
|
415
|
+
return this.jsonSchema();
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* The visitable in a visitor pattern. Used for exporting schema.
|
|
419
|
+
* @param {Exporter} visitor a schema exporter. @see JSONSchemaExporter
|
|
420
|
+
*/
|
|
421
|
+
// istanbul ignore next
|
|
422
|
+
export(visitor) {
|
|
423
|
+
throw new Error("Subclass must override");
|
|
424
|
+
}
|
|
425
|
+
properties() {
|
|
426
|
+
return this.__properties;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* @return JSON Schema with the schema version keyword at the root level.
|
|
430
|
+
*/
|
|
431
|
+
jsonSchema() {
|
|
432
|
+
const exporter = new JSONSchemaExporter();
|
|
433
|
+
return exporter.export(this);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Returns a validator function which throws ValidationError if the value it
|
|
437
|
+
* is asked to validate does not match the schema.
|
|
438
|
+
*
|
|
439
|
+
* Locks the current schema.
|
|
440
|
+
*
|
|
441
|
+
* @param {string} name the name of this schema (to distinguish errors)
|
|
442
|
+
* @param {*} [compiler] the ajv or equivalent JSON schema compiler to use
|
|
443
|
+
* @param {returnSchemaToo} [returnSchemaToo] whether to return jsonSchema as
|
|
444
|
+
* well as the validator
|
|
445
|
+
* @returns {Function} call on a value to validate it; throws on error
|
|
446
|
+
*/
|
|
447
|
+
compile(name, compiler, returnSchemaToo) {
|
|
448
|
+
assert.ok(name, "name is required");
|
|
449
|
+
if (!compiler) {
|
|
450
|
+
if (!ajv) {
|
|
451
|
+
ajv = new (require("ajv"))({
|
|
452
|
+
allErrors: true,
|
|
453
|
+
useDefaults: true,
|
|
454
|
+
strictSchema: false
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
compiler = ajv;
|
|
458
|
+
}
|
|
459
|
+
this.lock();
|
|
460
|
+
const jsonSchema = this.jsonSchema();
|
|
461
|
+
const validate2 = compiler.compile(jsonSchema);
|
|
462
|
+
const assertValid = (v) => {
|
|
463
|
+
if (!validate2(v)) {
|
|
464
|
+
throw new ValidationError(name, v, validate2.errors, jsonSchema);
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
if (returnSchemaToo) {
|
|
468
|
+
return { jsonSchema, assertValid };
|
|
469
|
+
}
|
|
470
|
+
return assertValid;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* See {@link compile}.
|
|
474
|
+
* @returns {Object} contains jsonSchema and assertValid
|
|
475
|
+
*/
|
|
476
|
+
getValidatorAndJSONSchema(name, compiler) {
|
|
477
|
+
return this.compile(name, compiler, true);
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* @return A copy of the Todea Schema object. Locked objects become unlocked.
|
|
481
|
+
*
|
|
482
|
+
*/
|
|
483
|
+
copy() {
|
|
484
|
+
const ret = new this.constructor();
|
|
485
|
+
ret.__properties = deepcopy(this.__properties);
|
|
486
|
+
ret.__isOptional = this.__isOptional;
|
|
487
|
+
return ret;
|
|
488
|
+
}
|
|
489
|
+
// max / min support
|
|
490
|
+
/**
|
|
491
|
+
* Validate input to min/max.
|
|
492
|
+
* @param {String} name Property name
|
|
493
|
+
* @param {Integer} val A non-negative integer for min/max.
|
|
494
|
+
*/
|
|
495
|
+
__validateRangeProperty(name, val) {
|
|
496
|
+
assert.ok(Number.isInteger(val), `${name} must be an integer`);
|
|
497
|
+
assert.ok(val >= 0, `${name} must be a non-negative number`);
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Set a min property depending on schema type.
|
|
501
|
+
* @param {Integer} val A non-negative integer for min/max.
|
|
502
|
+
*/
|
|
503
|
+
min(val) {
|
|
504
|
+
const name = this.constructor.MIN_PROP_NAME;
|
|
505
|
+
this.__validateRangeProperty(name, val);
|
|
506
|
+
const max = this.getProp(this.constructor.MAX_PROP_NAME);
|
|
507
|
+
assert.ok(max === void 0 || max >= val, "min must be less than max");
|
|
508
|
+
return this.__setProp(name, val);
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Set a max property depending on schema type.
|
|
512
|
+
* @param {Integer} val A non-negative integer for min/max.
|
|
513
|
+
*/
|
|
514
|
+
max(val) {
|
|
515
|
+
const name = this.constructor.MAX_PROP_NAME;
|
|
516
|
+
this.__validateRangeProperty(name, val);
|
|
517
|
+
const min = this.getProp(this.constructor.MIN_PROP_NAME);
|
|
518
|
+
assert.ok(min === void 0 || min <= val, "max must be more than min");
|
|
519
|
+
return this.__setProp(name, val);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
var ObjectSchema = class extends BaseSchema {
|
|
523
|
+
static JSON_SCHEMA_TYPE = "object";
|
|
524
|
+
static MAX_PROP_NAME = "maxProperties";
|
|
525
|
+
static MIN_PROP_NAME = "minProperties";
|
|
526
|
+
/**
|
|
527
|
+
* Creates an object schema object.
|
|
528
|
+
* @param {Object} [props={}] Keys must be strings, values must be schema
|
|
529
|
+
* objects. Passing props is the same as calling S.obj().props(props).
|
|
530
|
+
*/
|
|
531
|
+
constructor(props = {}) {
|
|
532
|
+
super();
|
|
533
|
+
this.objectSchemas = {};
|
|
534
|
+
this.patternSchemas = {};
|
|
535
|
+
this.props(props);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Set an object schema's object property.
|
|
539
|
+
* @param {String} name The name of the property.
|
|
540
|
+
* @param {BaseSchema} schema Any subclass of BaseSchema. Schema gets locked.
|
|
541
|
+
*/
|
|
542
|
+
prop(name, schema) {
|
|
543
|
+
assert.ok(
|
|
544
|
+
!this.__isLocked,
|
|
545
|
+
"Schema is locked. Call copy then further modify the schema"
|
|
546
|
+
);
|
|
547
|
+
assert.ok(typeof name === "string", "Property name must be strings.");
|
|
548
|
+
const properties = this.__setDefaultProp("properties", {});
|
|
549
|
+
assert.ok(
|
|
550
|
+
!Object.prototype.hasOwnProperty.call(properties, name),
|
|
551
|
+
`Property with key ${name} already exists`
|
|
552
|
+
);
|
|
553
|
+
assert.ok(schema !== void 0, `Property ${name} must define a schema`);
|
|
554
|
+
this.objectSchemas[name] = schema.lock();
|
|
555
|
+
properties[name] = schema.properties();
|
|
556
|
+
if (schema.required) {
|
|
557
|
+
this.__setDefaultProp("required", []).push(name);
|
|
558
|
+
}
|
|
559
|
+
return this;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* A mapping of property names to schemas. Calls this.prop() in a loop.
|
|
563
|
+
* @param {Object} props Keys must be strings, values must be schema
|
|
564
|
+
* objects.
|
|
565
|
+
*/
|
|
566
|
+
props(props) {
|
|
567
|
+
for (const [name, p] of Object.entries(props)) {
|
|
568
|
+
this.prop(name, p);
|
|
569
|
+
}
|
|
570
|
+
return this;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* A mapping of propertyProperties to schemas.
|
|
574
|
+
* @param {Object} props Keys must be regex, values must be schema
|
|
575
|
+
*/
|
|
576
|
+
patternProps(props) {
|
|
577
|
+
for (const [name, schema] of Object.entries(props)) {
|
|
578
|
+
const properties = this.__setDefaultProp("patternProperties", {});
|
|
579
|
+
assert.ok(
|
|
580
|
+
!Object.prototype.hasOwnProperty.call(properties, name),
|
|
581
|
+
`Pattern ${name} already exists`
|
|
582
|
+
);
|
|
583
|
+
const anchoredName = getAnchoredPattern(name);
|
|
584
|
+
this.patternSchemas[anchoredName] = schema.lock();
|
|
585
|
+
properties[anchoredName] = schema.properties();
|
|
586
|
+
}
|
|
587
|
+
return this;
|
|
588
|
+
}
|
|
589
|
+
copy() {
|
|
590
|
+
const ret = super.copy();
|
|
591
|
+
Object.assign(ret.objectSchemas, this.objectSchemas);
|
|
592
|
+
Object.assign(ret.patternSchemas, this.patternSchemas);
|
|
593
|
+
return ret;
|
|
594
|
+
}
|
|
595
|
+
properties() {
|
|
596
|
+
const ret = super.properties();
|
|
597
|
+
const hasProperty = Object.keys(this.objectSchemas).length > 0 || Object.keys(this.patternSchemas).length > 0;
|
|
598
|
+
const hasAdditionalProperties = !!this.additionalProperties;
|
|
599
|
+
ret.additionalProperties = !hasProperty || hasAdditionalProperties;
|
|
600
|
+
return ret;
|
|
601
|
+
}
|
|
602
|
+
export(visitor) {
|
|
603
|
+
return visitor.exportObject(this);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
var ArraySchema = class extends BaseSchema {
|
|
607
|
+
static JSON_SCHEMA_TYPE = "array";
|
|
608
|
+
static MAX_PROP_NAME = "maxItems";
|
|
609
|
+
static MIN_PROP_NAME = "minItems";
|
|
610
|
+
/**
|
|
611
|
+
* Creates an array schema object.
|
|
612
|
+
* @param {BaseSchema} [items] An optional parameter to items(). If provided,
|
|
613
|
+
* it is the same as calling S.arr().items(items).
|
|
614
|
+
*/
|
|
615
|
+
constructor(items) {
|
|
616
|
+
super();
|
|
617
|
+
this.itemsSchema = void 0;
|
|
618
|
+
if (items) {
|
|
619
|
+
this.items(items);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Set the schema for items in array
|
|
624
|
+
* @param {BaseSchema} items Any subclass of BaseSchema. Schema gets locked.
|
|
625
|
+
*/
|
|
626
|
+
items(items) {
|
|
627
|
+
assert.ok(!this.itemsSchema, "Items is already set.");
|
|
628
|
+
this.itemsSchema = items.lock();
|
|
629
|
+
this.__setProp("items", items.properties());
|
|
630
|
+
return this;
|
|
631
|
+
}
|
|
632
|
+
copy() {
|
|
633
|
+
const ret = super.copy();
|
|
634
|
+
ret.itemsSchema = this.itemsSchema;
|
|
635
|
+
return ret;
|
|
636
|
+
}
|
|
637
|
+
export(visitor) {
|
|
638
|
+
return visitor.exportArray(this);
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
var NumberSchema = class extends BaseSchema {
|
|
642
|
+
static JSON_SCHEMA_TYPE = "number";
|
|
643
|
+
static MAX_PROP_NAME = "maximum";
|
|
644
|
+
static MIN_PROP_NAME = "minimum";
|
|
645
|
+
constructor() {
|
|
646
|
+
super();
|
|
647
|
+
this.__isFloat = false;
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Validate input to min/max.
|
|
651
|
+
* @param {String} name Property name
|
|
652
|
+
* @param {Integer} val A finite number for min/max.
|
|
653
|
+
*/
|
|
654
|
+
__validateRangeProperty(name, val) {
|
|
655
|
+
assert.ok(Number.isFinite(val), `${name} must be a number`);
|
|
656
|
+
}
|
|
657
|
+
asFloat() {
|
|
658
|
+
assert(!this.__isLocked, "Schema is locked");
|
|
659
|
+
this.__isFloat = true;
|
|
660
|
+
return this;
|
|
661
|
+
}
|
|
662
|
+
get isFloat() {
|
|
663
|
+
return this.__isFloat;
|
|
664
|
+
}
|
|
665
|
+
export(visitor) {
|
|
666
|
+
return visitor.exportNumber(this);
|
|
667
|
+
}
|
|
668
|
+
copy() {
|
|
669
|
+
const ret = super.copy();
|
|
670
|
+
ret.__isFloat = this.__isFloat;
|
|
671
|
+
return ret;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
var IntegerSchema = class extends NumberSchema {
|
|
675
|
+
static JSON_SCHEMA_TYPE = "integer";
|
|
676
|
+
/**
|
|
677
|
+
* Validate input to min/max.
|
|
678
|
+
* @param {String} name Property name
|
|
679
|
+
* @param {Integer} val An integer for min/max.
|
|
680
|
+
*/
|
|
681
|
+
__validateRangeProperty(name, val) {
|
|
682
|
+
assert.ok(Number.isInteger(val), `${name} must be an integer`);
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* sets limit on how large max or min can be.
|
|
686
|
+
* Validates current min/max to ensure they work correctly
|
|
687
|
+
*/
|
|
688
|
+
__setSafeRangeLimit(val) {
|
|
689
|
+
const max = this.getProp(this.constructor.MAX_PROP_NAME);
|
|
690
|
+
if (max === void 0) {
|
|
691
|
+
this.max(val);
|
|
692
|
+
} else {
|
|
693
|
+
assert.ok(max <= val, `max cannot exceed ${val}`);
|
|
694
|
+
}
|
|
695
|
+
const min = this.getProp(this.constructor.MIN_PROP_NAME);
|
|
696
|
+
if (min === void 0) {
|
|
697
|
+
this.min(-val);
|
|
698
|
+
} else {
|
|
699
|
+
assert.ok(min >= -val, `min must be larger than ${-val}`);
|
|
700
|
+
}
|
|
701
|
+
return this;
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* applies range for Int32 values
|
|
705
|
+
*/
|
|
706
|
+
asInt32() {
|
|
707
|
+
return this.__setSafeRangeLimit(INT32_MAX);
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* applies range for int64 values
|
|
711
|
+
*/
|
|
712
|
+
asInt64() {
|
|
713
|
+
return this.__setSafeRangeLimit(INT64_MAX);
|
|
714
|
+
}
|
|
715
|
+
asFloat = void 0;
|
|
716
|
+
export(visitor) {
|
|
717
|
+
return visitor.exportInteger(this);
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
var StringSchema = class extends BaseSchema {
|
|
721
|
+
static JSON_SCHEMA_TYPE = "string";
|
|
722
|
+
static MAX_PROP_NAME = "maxLength";
|
|
723
|
+
static MIN_PROP_NAME = "minLength";
|
|
724
|
+
/**
|
|
725
|
+
* Set valid values for the string schema.
|
|
726
|
+
* @param {Array<String>} validValues Valid values for the string. There must
|
|
727
|
+
* be at least 2 valid values.
|
|
728
|
+
*/
|
|
729
|
+
enum(validValues) {
|
|
730
|
+
const values = Array.isArray(validValues) ? validValues : [...arguments];
|
|
731
|
+
assert(values.length >= 1, "Enum must contain at least 1 value.");
|
|
732
|
+
return this.__setProp("enum", values);
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* A pattern for the string.
|
|
736
|
+
* @param {String|RegExp} pattern The pattern for the string. Can be a string
|
|
737
|
+
* with regex syntax, or a RegExp object.
|
|
738
|
+
*/
|
|
739
|
+
pattern(pattern) {
|
|
740
|
+
if (pattern instanceof RegExp) {
|
|
741
|
+
pattern = pattern.source;
|
|
742
|
+
}
|
|
743
|
+
assert(typeof pattern === "string", "Pattern must be a string");
|
|
744
|
+
const anchoredPattern = getAnchoredPattern(pattern);
|
|
745
|
+
return this.__setProp("pattern", anchoredPattern);
|
|
746
|
+
}
|
|
747
|
+
export(visitor) {
|
|
748
|
+
return visitor.exportString(this);
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
var BooleanSchema = class extends BaseSchema {
|
|
752
|
+
static JSON_SCHEMA_TYPE = "boolean";
|
|
753
|
+
export(visitor) {
|
|
754
|
+
return visitor.exportBoolean(this);
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
var MapSchema = class extends ObjectSchema {
|
|
758
|
+
constructor() {
|
|
759
|
+
super();
|
|
760
|
+
this.prop = void 0;
|
|
761
|
+
this.props = void 0;
|
|
762
|
+
this.patternProps = void 0;
|
|
763
|
+
this.finalized = false;
|
|
764
|
+
this.keySchema = void 0;
|
|
765
|
+
this.valueSchema = void 0;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Set a key pattern for the map.
|
|
769
|
+
* @param {String} keyPattern A pattern for keys
|
|
770
|
+
*/
|
|
771
|
+
keyPattern(pattern) {
|
|
772
|
+
assert(!this.keySchema, "key pattern already set");
|
|
773
|
+
this.keySchema = S2.str.pattern(pattern).lock();
|
|
774
|
+
this.__tryFinalizeSchema();
|
|
775
|
+
return this;
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Set a value schema for the map.
|
|
779
|
+
* @param {BaseSchema} value Any subclass of BaseSchema for the values of map
|
|
780
|
+
*/
|
|
781
|
+
value(value) {
|
|
782
|
+
assert(!this.valueSchema, "value schema already set");
|
|
783
|
+
assert(value.required, "value must be required");
|
|
784
|
+
this.valueSchema = value.lock();
|
|
785
|
+
this.__tryFinalizeSchema();
|
|
786
|
+
return this;
|
|
787
|
+
}
|
|
788
|
+
lock() {
|
|
789
|
+
this.__finalizeSchema();
|
|
790
|
+
return super.lock();
|
|
791
|
+
}
|
|
792
|
+
__finalizeSchema() {
|
|
793
|
+
assert(this.valueSchema, "Must have a value schema");
|
|
794
|
+
if (!this.keySchema) {
|
|
795
|
+
this.keySchema = S2.str;
|
|
796
|
+
}
|
|
797
|
+
this.__tryFinalizeSchema();
|
|
798
|
+
}
|
|
799
|
+
__tryFinalizeSchema() {
|
|
800
|
+
if (this.keySchema && this.valueSchema && !this.finalized) {
|
|
801
|
+
this.finalized = true;
|
|
802
|
+
super.patternProps({
|
|
803
|
+
[this.keySchema?.getProp("pattern") ?? ".*"]: this.valueSchema
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
export(visitor) {
|
|
808
|
+
this.__finalizeSchema();
|
|
809
|
+
return visitor.exportMap(this);
|
|
810
|
+
}
|
|
811
|
+
copy() {
|
|
812
|
+
const ret = super.copy();
|
|
813
|
+
ret.finalized = this.finalized;
|
|
814
|
+
ret.keySchema = this.keySchema.copy();
|
|
815
|
+
ret.valueSchema = this.valueSchema.copy();
|
|
816
|
+
return ret;
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
var MediaSchema = class extends StringSchema {
|
|
820
|
+
type(t) {
|
|
821
|
+
this.__setProp("contentMediaType", t);
|
|
822
|
+
return this;
|
|
823
|
+
}
|
|
824
|
+
encoding(e) {
|
|
825
|
+
assert(
|
|
826
|
+
["binary", "base64", "utf-8"].includes(e),
|
|
827
|
+
"Encoding must be binary, base64 or utf-8"
|
|
828
|
+
);
|
|
829
|
+
this.__setProp("contentEncoding", e);
|
|
830
|
+
return this;
|
|
831
|
+
}
|
|
832
|
+
export(visitor) {
|
|
833
|
+
return visitor.exportMedia(this);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
var JSONSchemaExporter = class {
|
|
837
|
+
constructor() {
|
|
838
|
+
const methods = [
|
|
839
|
+
"exportString",
|
|
840
|
+
"exportInteger",
|
|
841
|
+
"exportNumber",
|
|
842
|
+
"exportObject",
|
|
843
|
+
"exportArray",
|
|
844
|
+
"exportBoolean",
|
|
845
|
+
"exportMap",
|
|
846
|
+
"exportMedia"
|
|
847
|
+
];
|
|
848
|
+
for (const method of methods) {
|
|
849
|
+
Object.defineProperty(this, method, {
|
|
850
|
+
get: () => {
|
|
851
|
+
return (schema) => {
|
|
852
|
+
return schema.properties();
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
export(schema) {
|
|
859
|
+
const ret = deepcopy(schema.export(this));
|
|
860
|
+
ret.$schema = "http://json-schema.org/draft-07/schema#";
|
|
861
|
+
return ret;
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
var S2 = class _S {
|
|
865
|
+
/**
|
|
866
|
+
* @param {Object} object See {@link ObjectSchema#constructor}
|
|
867
|
+
* @return A new ObjectSchema object.
|
|
868
|
+
*/
|
|
869
|
+
static obj(object) {
|
|
870
|
+
return new ObjectSchema(object);
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* @param {BaseSchema} schema See {@link ArraySchema#constructor}
|
|
874
|
+
* @return A new ArraySchema object.
|
|
875
|
+
*/
|
|
876
|
+
static arr(schema) {
|
|
877
|
+
return new ArraySchema(schema);
|
|
878
|
+
}
|
|
879
|
+
/**
|
|
880
|
+
* Get a new NumberSchema object.
|
|
881
|
+
*/
|
|
882
|
+
static get double() {
|
|
883
|
+
return new NumberSchema();
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Get a new IntegerSchema object.
|
|
887
|
+
*/
|
|
888
|
+
static get int() {
|
|
889
|
+
return new IntegerSchema();
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Get a new StringSchema object.
|
|
893
|
+
*/
|
|
894
|
+
static get str() {
|
|
895
|
+
return new StringSchema();
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Get a new BooleanSchema object.
|
|
899
|
+
*/
|
|
900
|
+
static get bool() {
|
|
901
|
+
return new BooleanSchema();
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Get a new MapSchema object.
|
|
905
|
+
*/
|
|
906
|
+
static get map() {
|
|
907
|
+
return new MapSchema();
|
|
908
|
+
}
|
|
909
|
+
/**
|
|
910
|
+
* Get a new MediaSchema object.
|
|
911
|
+
*/
|
|
912
|
+
static get media() {
|
|
913
|
+
return new MediaSchema();
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Lock all schemas in a dictionary (in-place).
|
|
917
|
+
* @param {Object<Schema>} schemas a map of schema values
|
|
918
|
+
* @returns the input map of schema values
|
|
919
|
+
*/
|
|
920
|
+
static lock(schemas) {
|
|
921
|
+
Object.values(schemas).forEach((x) => x.lock());
|
|
922
|
+
return schemas;
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Sets all schemas as optional (in-place).
|
|
926
|
+
* @param {Object<Schema>} schemas a map of schema values
|
|
927
|
+
* @returns the input map of schema values
|
|
928
|
+
*/
|
|
929
|
+
static optional(schemas) {
|
|
930
|
+
Object.values(schemas).forEach((x) => x.optional());
|
|
931
|
+
return schemas;
|
|
932
|
+
}
|
|
933
|
+
static PATTERN = {
|
|
934
|
+
UUID_PATTERN: /^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/
|
|
935
|
+
};
|
|
936
|
+
/**
|
|
937
|
+
* Common schemas.
|
|
938
|
+
*/
|
|
939
|
+
static SCHEMAS = _S.lock({
|
|
940
|
+
UUID: _S.str.desc("An UUID. It is normally generated by calling uuidv4().").pattern(_S.PATTERN.UUID_PATTERN),
|
|
941
|
+
STR_ANDU: _S.str.desc("Only hyphens, underscores, letters and numbers are permitted.").pattern(/^[-_a-zA-Z0-9]+$/),
|
|
942
|
+
// oversimplified, quick regex to check that a string looks like an email
|
|
943
|
+
STR_EMAIL: _S.str.pattern(/^[^A-Z ]+@.+$/).desc("an e-mail address (lowercase only)").lock(),
|
|
944
|
+
TIMESTAMP: _S.str.pattern(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d{3}Z/).desc(`An UTC timestamp with millisecond precision, for example,
|
|
945
|
+
2021-02-15T20:15:59.321Z`),
|
|
946
|
+
TIMESTAMP_WITH_TZ: _S.str.pattern(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(\.\d*)?([+-][0-2]\d:[0-5]\d|Z)/).desc(`Timestamp with time zone and optional millisecond precision,
|
|
947
|
+
for example,
|
|
948
|
+
2021-02-15T20:15:59Z,
|
|
949
|
+
2022-09-15T16:48:28.9097226Z,
|
|
950
|
+
2021-02-15T11:55:20-05:00,
|
|
951
|
+
2021-02-15T11:55:20.9097226+08:00`),
|
|
952
|
+
EPOCH_IN_SECONDS: _S.int.min(EPOCH_IN_SECONDS_MIN).max(EPOCH_IN_SECONDS_MAX).desc(`Unix epoch time format in seconds from
|
|
953
|
+
${TIMESTAMP_MIN} to ${TIMESTAMP_MAX}.`),
|
|
954
|
+
EPOCH_IN_MILLISECONDS: _S.int.min(EPOCH_IN_MILLISECONDS_MIN).max(EPOCH_IN_MILLISECONDS_MAX).desc(`Unix epoch time format in
|
|
955
|
+
milliseconds from ${TIMESTAMP_MIN} to ${TIMESTAMP_MAX}.`).asInt64()
|
|
956
|
+
});
|
|
957
|
+
/** Thrown if validation fails. */
|
|
958
|
+
static ValidationError = ValidationError;
|
|
959
|
+
static INT32_MAX = INT32_MAX;
|
|
960
|
+
static INT32_MIN = INT32_MIN;
|
|
961
|
+
static INT64_MAX = INT64_MAX;
|
|
962
|
+
static INT64_MIN = INT64_MIN;
|
|
963
|
+
};
|
|
964
|
+
function getAnchoredPattern(pattern) {
|
|
965
|
+
let anchoredName = pattern;
|
|
966
|
+
if (pattern[0] !== "^") {
|
|
967
|
+
anchoredName = "^" + pattern;
|
|
968
|
+
}
|
|
969
|
+
if (pattern[pattern.length - 1] !== "$") {
|
|
970
|
+
anchoredName += "$";
|
|
971
|
+
}
|
|
972
|
+
return anchoredName;
|
|
973
|
+
}
|
|
974
|
+
module2.exports = S2;
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
// src/index.ts
|
|
979
|
+
var index_exports = {};
|
|
980
|
+
__export(index_exports, {
|
|
981
|
+
VERSION: () => VERSION,
|
|
982
|
+
specSchema: () => spec_schema_default2,
|
|
983
|
+
validate: () => validate
|
|
984
|
+
});
|
|
985
|
+
module.exports = __toCommonJS(index_exports);
|
|
986
|
+
|
|
987
|
+
// package.json
|
|
988
|
+
var package_default = {
|
|
989
|
+
name: "@polytric/openws-spec",
|
|
990
|
+
version: "0.0.2",
|
|
991
|
+
description: "Polytric OpenWS Specification",
|
|
992
|
+
type: "module",
|
|
993
|
+
main: "./dist/index.js",
|
|
994
|
+
types: "./dist/index.d.ts",
|
|
995
|
+
exports: {
|
|
996
|
+
".": {
|
|
997
|
+
types: "./dist/index.d.ts",
|
|
998
|
+
import: "./dist/index.js",
|
|
999
|
+
require: "./dist/index.cjs"
|
|
1000
|
+
},
|
|
1001
|
+
"./builder": {
|
|
1002
|
+
types: "./dist/builder.d.ts",
|
|
1003
|
+
import: "./dist/builder.js",
|
|
1004
|
+
require: "./dist/builder.cjs"
|
|
1005
|
+
},
|
|
1006
|
+
"./types": {
|
|
1007
|
+
types: "./dist/types.d.ts",
|
|
1008
|
+
import: "./dist/types.js",
|
|
1009
|
+
require: "./dist/types.cjs"
|
|
1010
|
+
}
|
|
1011
|
+
},
|
|
1012
|
+
files: [
|
|
1013
|
+
"dist",
|
|
1014
|
+
"LICENSE",
|
|
1015
|
+
"README.md"
|
|
1016
|
+
],
|
|
1017
|
+
keywords: [
|
|
1018
|
+
"openws",
|
|
1019
|
+
"specification",
|
|
1020
|
+
"websocket"
|
|
1021
|
+
],
|
|
1022
|
+
author: "Polytric",
|
|
1023
|
+
license: "Apache-2.0",
|
|
1024
|
+
scripts: {
|
|
1025
|
+
build: "pnpm emit && tsup",
|
|
1026
|
+
emit: `tsx -e "import schema from './src/spec-schema.ts'; console.log(JSON.stringify(schema.jsonSchema()))" > ./src/spec-schema.json`,
|
|
1027
|
+
prepublishOnly: "pnpm build",
|
|
1028
|
+
"test:builder": "nodemon -w dist -w test/builder.cjs test/builder.cjs",
|
|
1029
|
+
"test:validate": "tsx test/validate-spec.ts",
|
|
1030
|
+
typecheck: "tsc --noEmit"
|
|
1031
|
+
},
|
|
1032
|
+
dependencies: {
|
|
1033
|
+
ajv: "^8.17.1"
|
|
1034
|
+
},
|
|
1035
|
+
devDependencies: {
|
|
1036
|
+
"@pocketgems/schema": "^0.1.3",
|
|
1037
|
+
nodemon: "^3.1.11",
|
|
1038
|
+
tsup: "^8.5.1",
|
|
1039
|
+
tsx: "^4.21.0",
|
|
1040
|
+
typescript: "^5.9.3"
|
|
1041
|
+
},
|
|
1042
|
+
packageManager: "pnpm@10.26.1",
|
|
1043
|
+
publishConfig: {
|
|
1044
|
+
access: "public"
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
|
|
1048
|
+
// src/spec-schema.ts
|
|
1049
|
+
var import_schema = __toESM(require_schema(), 1);
|
|
1050
|
+
var keyPattern = "[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?";
|
|
1051
|
+
var messageSchema = import_schema.default.obj({
|
|
1052
|
+
payload: import_schema.default.obj({}).desc(
|
|
1053
|
+
"Must be a valid JSON schema spec. For brevity, openws omits this spec, but implementations should valid this"
|
|
1054
|
+
),
|
|
1055
|
+
description: import_schema.default.str.optional(),
|
|
1056
|
+
from: import_schema.default.arr(import_schema.default.str).desc("A list of roles that can send this message").optional()
|
|
1057
|
+
});
|
|
1058
|
+
messageSchema.additionalProperties = true;
|
|
1059
|
+
var endpointSchema = import_schema.default.obj({
|
|
1060
|
+
host: import_schema.default.str,
|
|
1061
|
+
port: import_schema.default.int.min(1).max(65535),
|
|
1062
|
+
path: import_schema.default.str
|
|
1063
|
+
});
|
|
1064
|
+
endpointSchema.additionalProperties = true;
|
|
1065
|
+
var roleSchema = import_schema.default.obj({
|
|
1066
|
+
endpoints: import_schema.default.arr(endpointSchema).min(1).optional().desc(
|
|
1067
|
+
"A role can declare an endpoint to accept connections from other roles, normally used by servers"
|
|
1068
|
+
),
|
|
1069
|
+
messages: import_schema.default.map.keyPattern(keyPattern).value(messageSchema).desc(
|
|
1070
|
+
"A message accepted by the role and handled by the role, and roles can send messages other roles accepts. The OpenWS spec only defines the shape of the payload, and how things get encoded / decoded on the wire, it doesn't determine behavior (through through description the behavior can be documented)."
|
|
1071
|
+
),
|
|
1072
|
+
description: import_schema.default.str.optional()
|
|
1073
|
+
});
|
|
1074
|
+
roleSchema.additionalProperties = true;
|
|
1075
|
+
var networkSchema = import_schema.default.obj({
|
|
1076
|
+
roles: import_schema.default.map.min(1).keyPattern(keyPattern).desc(
|
|
1077
|
+
"A network is a collection of roles that exchange messages. Multiple roles can coexist in the same network. The simplest network contains a server-client pair."
|
|
1078
|
+
).value(roleSchema),
|
|
1079
|
+
description: import_schema.default.str.optional()
|
|
1080
|
+
});
|
|
1081
|
+
networkSchema.additionalProperties = true;
|
|
1082
|
+
var openWsSchema = import_schema.default.obj({
|
|
1083
|
+
openws: import_schema.default.str.enum("0.0.1", "0.0.2").desc("The OpenWS schema version"),
|
|
1084
|
+
title: import_schema.default.str.desc("A title for the overall system.").optional(),
|
|
1085
|
+
description: import_schema.default.str.desc(
|
|
1086
|
+
"A high level description of the overall system, including all networks and all roles"
|
|
1087
|
+
).optional(),
|
|
1088
|
+
version: import_schema.default.str.desc("A version string").optional(),
|
|
1089
|
+
networks: import_schema.default.map.min(1).keyPattern(keyPattern).value(networkSchema)
|
|
1090
|
+
});
|
|
1091
|
+
openWsSchema.additionalProperties = true;
|
|
1092
|
+
var spec_schema_default = openWsSchema;
|
|
1093
|
+
|
|
1094
|
+
// src/spec-schema.json
|
|
1095
|
+
var spec_schema_default2 = { type: "object", properties: { openws: { type: "string", enum: ["0.0.1", "0.0.2"], description: "The OpenWS schema version" }, title: { type: "string", description: "A title for the overall system." }, description: { type: "string", description: "A high level description of the overall system, including all networks and all roles" }, version: { type: "string", description: "A version string" }, networks: { type: "object", minProperties: 1, patternProperties: { "^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$": { type: "object", properties: { roles: { type: "object", minProperties: 1, description: "A network is a collection of roles that exchange messages. Multiple roles can coexist in the same network. The simplest network contains a server-client pair.", patternProperties: { "^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$": { type: "object", properties: { endpoints: { type: "array", items: { type: "object", properties: { host: { type: "string" }, port: { type: "integer", minimum: 1, maximum: 65535 }, path: { type: "string" } }, required: ["host", "port", "path"], additionalProperties: true }, minItems: 1, description: "A role can declare an endpoint to accept connections from other roles, normally used by servers" }, messages: { type: "object", patternProperties: { "^[A-Za-z](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$": { type: "object", properties: { payload: { type: "object", description: "Must be a valid JSON schema spec. For brevity, openws omits this spec, but implementations should valid this", additionalProperties: true }, description: { type: "string" }, from: { type: "array", items: { type: "string" }, description: "A list of roles that can send this message" } }, required: ["payload"], additionalProperties: true } }, description: "A message accepted by the role and handled by the role, and roles can send messages other roles accepts. The OpenWS spec only defines the shape of the payload, and how things get encoded / decoded on the wire, it doesn't determine behavior (through through description the behavior can be documented).", additionalProperties: false }, description: { type: "string" } }, required: ["messages"], additionalProperties: true } }, additionalProperties: false }, description: { type: "string" } }, required: ["roles"], additionalProperties: true } }, additionalProperties: false } }, required: ["openws", "networks"], additionalProperties: true, $schema: "http://json-schema.org/draft-07/schema#" };
|
|
1096
|
+
|
|
1097
|
+
// src/index.ts
|
|
1098
|
+
var VERSION = package_default.version;
|
|
1099
|
+
var validator;
|
|
1100
|
+
function validate(spec) {
|
|
1101
|
+
validator = validator ?? spec_schema_default.compile("Validator");
|
|
1102
|
+
validator(spec);
|
|
1103
|
+
}
|
|
1104
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1105
|
+
0 && (module.exports = {
|
|
1106
|
+
VERSION,
|
|
1107
|
+
specSchema,
|
|
1108
|
+
validate
|
|
1109
|
+
});
|
|
1110
|
+
//# sourceMappingURL=index.cjs.map
|