adapt-authoring-jsonschema 0.0.1
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/.eslintignore +1 -0
- package/.eslintrc +14 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +55 -0
- package/.github/ISSUE_TEMPLATE/config.yml +1 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +22 -0
- package/.github/dependabot.yml +11 -0
- package/.github/pull_request_template.md +25 -0
- package/.github/workflows/labelled_prs.yml +16 -0
- package/.github/workflows/new.yml +19 -0
- package/adapt-authoring.json +13 -0
- package/bin/check.js +43 -0
- package/conf/config.schema.json +26 -0
- package/docs/plugins/schemas-reference.js +74 -0
- package/docs/plugins/schemas-reference.md +7 -0
- package/docs/schema-examples.md +144 -0
- package/docs/schemas-introduction.md +78 -0
- package/docs/writing-a-schema.md +194 -0
- package/errors/errors.json +52 -0
- package/index.js +5 -0
- package/lib/JsonSchema.js +268 -0
- package/lib/JsonSchemaModule.js +209 -0
- package/lib/Keywords.js +74 -0
- package/lib/XSSDefaults.js +142 -0
- package/lib/typedefs.js +48 -0
- package/package.json +29 -0
- package/schema/base.schema.json +13 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { AbstractModule, Hook } from 'adapt-authoring-core'
|
|
3
|
+
import Ajv from 'ajv/dist/2020.js'
|
|
4
|
+
import { glob } from 'glob'
|
|
5
|
+
import JsonSchema from './JsonSchema.js'
|
|
6
|
+
import Keywords from './Keywords.js'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import safeRegex from 'safe-regex'
|
|
9
|
+
import XSSDefaults from './XSSDefaults.js'
|
|
10
|
+
|
|
11
|
+
const BASE_SCHEMA_PATH = './schema/base.schema.json'
|
|
12
|
+
/**
|
|
13
|
+
* Module which add support for the JSON Schema specification
|
|
14
|
+
* @memberof jsonschema
|
|
15
|
+
* @extends {AbstractModule}
|
|
16
|
+
*/
|
|
17
|
+
class JsonSchemaModule extends AbstractModule {
|
|
18
|
+
/** @override */
|
|
19
|
+
async init () {
|
|
20
|
+
this.app.jsonschema = this
|
|
21
|
+
/**
|
|
22
|
+
* Reference to all registed schemas
|
|
23
|
+
* @type {Object}
|
|
24
|
+
*/
|
|
25
|
+
this.schemas = {}
|
|
26
|
+
/**
|
|
27
|
+
* Temporary store of extension schemas
|
|
28
|
+
* @type {Object}
|
|
29
|
+
*/
|
|
30
|
+
this.schemaExtensions = {}
|
|
31
|
+
/**
|
|
32
|
+
* Invoked when schemas are registered
|
|
33
|
+
* @type {Hook}
|
|
34
|
+
*/
|
|
35
|
+
this.registerSchemasHook = new Hook
|
|
36
|
+
/**
|
|
37
|
+
* Tags and attributes to be whitelisted by the XSS filter
|
|
38
|
+
* @type {Object}
|
|
39
|
+
*/
|
|
40
|
+
this.xssWhitelist = {}
|
|
41
|
+
/**
|
|
42
|
+
* Reference to the Ajv instance
|
|
43
|
+
* @type {external:Ajv}
|
|
44
|
+
*/
|
|
45
|
+
this.validator = new Ajv({
|
|
46
|
+
addUsedSchema: false,
|
|
47
|
+
allErrors: true,
|
|
48
|
+
allowUnionTypes: true,
|
|
49
|
+
loadSchema: this.getSchema.bind(this),
|
|
50
|
+
removeAdditional: 'all',
|
|
51
|
+
strict: false,
|
|
52
|
+
verbose: true,
|
|
53
|
+
keywords: Keywords.all
|
|
54
|
+
})
|
|
55
|
+
this.addStringFormats({
|
|
56
|
+
'date-time': /[A-za-z0-9:+\(\)]+/,
|
|
57
|
+
time: /^(\d{2}):(\d{2}):(\d{2})\+(\d{2}):(\d{2})$/,
|
|
58
|
+
uri: /^(.+):\/\/(www\.)?[-a-zA-Z0-9@:%_\+.~#?&//=]{1,256}/
|
|
59
|
+
})
|
|
60
|
+
await this.resetSchemaRegistry()
|
|
61
|
+
|
|
62
|
+
this.onReady()
|
|
63
|
+
.then(() => this.app.waitForModule('config', 'errors'))
|
|
64
|
+
.then(() => {
|
|
65
|
+
Object.assign(this.xssWhitelist,
|
|
66
|
+
this.getConfig('xssWhitelistOverride') ? {} : XSSDefaults,
|
|
67
|
+
this.getConfig('xssWhitelist'))
|
|
68
|
+
})
|
|
69
|
+
.then(() => this.addStringFormats(this.getConfig('formatOverrides')))
|
|
70
|
+
.then(() => this.registerSchemas())
|
|
71
|
+
.catch(e => this.log('error', e))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Empties the schema registry (with the exception of the base schema)
|
|
76
|
+
*/
|
|
77
|
+
async resetSchemaRegistry () {
|
|
78
|
+
this.log('debug', 'RESET_SCHEMAS')
|
|
79
|
+
this.schemas = {
|
|
80
|
+
base: await this.createSchema(path.resolve(this.rootDir, BASE_SCHEMA_PATH), { enableCache: true })
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Adds string formats to the Ajv validator
|
|
86
|
+
*/
|
|
87
|
+
addStringFormats (formats) {
|
|
88
|
+
Object.entries(formats).forEach(([name, re]) => {
|
|
89
|
+
const isUnsafe = !safeRegex(re)
|
|
90
|
+
if (isUnsafe) this.log('warn', `unsafe RegExp for format '${name}' (${re}), using default`)
|
|
91
|
+
this.validator.addFormat(name, isUnsafe ? /.*/ : re)
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Adds a new keyword to be used in JSON schemas
|
|
97
|
+
* @param {AjvKeyword} definition
|
|
98
|
+
*/
|
|
99
|
+
addKeyword (definition) {
|
|
100
|
+
try {
|
|
101
|
+
this.validator.addKeyword(definition)
|
|
102
|
+
} catch (e) {
|
|
103
|
+
this.log('warn', `failed to define keyword '${definition.keyword}', ${e}`)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Searches all Adapt dependencies for any local JSON schemas and registers them for use in the app. Schemas must be located in in a `/schema` folder, and be named appropriately: `*.schema.json`.
|
|
109
|
+
* @return {Promise}
|
|
110
|
+
*/
|
|
111
|
+
async registerSchemas () {
|
|
112
|
+
await this.resetSchemaRegistry()
|
|
113
|
+
await Promise.all(Object.values(this.app.dependencies).map(async d => {
|
|
114
|
+
if(d.name === this.name) return
|
|
115
|
+
const files = await glob('schema/*.schema.json', { cwd: d.rootDir, absolute: true })
|
|
116
|
+
;(await Promise.allSettled(files.map(f => this.registerSchema(f))))
|
|
117
|
+
.filter(r => r.status === 'rejected')
|
|
118
|
+
.forEach(r => this.log('warn', r.reason))
|
|
119
|
+
}))
|
|
120
|
+
this.registerSchemasHook.invoke();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Registers a single JSON schema for use in the app
|
|
125
|
+
* @param {String} filePath Path to the schema file
|
|
126
|
+
* @param {RegisterSchemaOptions} options Extra options
|
|
127
|
+
* @return {Promise}
|
|
128
|
+
*/
|
|
129
|
+
async registerSchema (filePath, options = {}) {
|
|
130
|
+
if (!_.isString(filePath)) {
|
|
131
|
+
throw this.app.errors.INVALID_PARAMS.setData({ params: ['filePath'] })
|
|
132
|
+
}
|
|
133
|
+
const schema = await this.createSchema(filePath, options)
|
|
134
|
+
|
|
135
|
+
if (this.schemas[schema.name]) {
|
|
136
|
+
if (options.replace) this.deregisterSchema(schema.name)
|
|
137
|
+
else throw this.app.errors.SCHEMA_EXISTS.setData({ schemaName: schema.name, filePath })
|
|
138
|
+
}
|
|
139
|
+
this.schemas[schema.name] = schema
|
|
140
|
+
this.schemaExtensions?.[schema.name]?.forEach(s => schema.addExtension(s))
|
|
141
|
+
if (schema.raw.$patch) this.extendSchema(schema.raw.$patch?.source?.$ref, schema.name)
|
|
142
|
+
|
|
143
|
+
this.log('debug', 'REGISTER_SCHEMA', schema.name, filePath)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* deregisters a single JSON schema
|
|
148
|
+
* @param {String} name Schem name to deregister
|
|
149
|
+
* @return {Promise} Resolves with schema data
|
|
150
|
+
*/
|
|
151
|
+
deregisterSchema (name) {
|
|
152
|
+
if (this.schemas[name]) delete this.schemas[name]
|
|
153
|
+
// remove schema from any extensions lists
|
|
154
|
+
Object.entries(this.schemaExtensions).forEach(([base, extensions]) => {
|
|
155
|
+
this.schemaExtensions[base] = extensions.filter(s => s !== name)
|
|
156
|
+
})
|
|
157
|
+
this.log('debug', 'DEREGISTER_SCHEMA', name)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Creates a new JsonSchema instance
|
|
162
|
+
* @param {String} filePath Path to the schema file
|
|
163
|
+
* @param {Object} options Options passed to JsonSchema constructor
|
|
164
|
+
* @returns {JsonSchema}
|
|
165
|
+
*/
|
|
166
|
+
createSchema (filePath, options) {
|
|
167
|
+
const schema = new JsonSchema({
|
|
168
|
+
enableCache: this.getConfig('enableCache'),
|
|
169
|
+
filePath,
|
|
170
|
+
validator: this.validator,
|
|
171
|
+
xssWhitelist: this.xssWhitelist,
|
|
172
|
+
...options
|
|
173
|
+
})
|
|
174
|
+
this.schemaExtensions?.[schema.name]?.forEach(s => schema.addExtension(s))
|
|
175
|
+
delete this.schemaExtensions?.[schema.name]
|
|
176
|
+
return schema.load()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Extends an existing schema with extra properties
|
|
181
|
+
* @param {String} baseSchemaName The name of the schema to extend
|
|
182
|
+
* @param {String} extSchemaName The name of the schema to extend with
|
|
183
|
+
*/
|
|
184
|
+
extendSchema (baseSchemaName, extSchemaName) {
|
|
185
|
+
const baseSchema = this.schemas[baseSchemaName]
|
|
186
|
+
if (baseSchema) {
|
|
187
|
+
baseSchema.addExtension(extSchemaName)
|
|
188
|
+
} else {
|
|
189
|
+
if (!this.schemaExtensions[baseSchemaName]) this.schemaExtensions[baseSchemaName] = []
|
|
190
|
+
this.schemaExtensions[baseSchemaName].push(extSchemaName)
|
|
191
|
+
}
|
|
192
|
+
this.log('debug', 'EXTEND_SCHEMA', baseSchemaName, extSchemaName)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Retrieves the specified schema. Recursively applies any schema merge/patch schemas. Will returned cached data if enabled.
|
|
197
|
+
* @param {String} schemaName The name of the schema to return
|
|
198
|
+
* @param {LoadSchemaOptions} options
|
|
199
|
+
* @param {Boolean} options.compiled If false, the raw schema will be returned
|
|
200
|
+
* @return {Promise} The compiled schema validation function (default) or the raw schema
|
|
201
|
+
*/
|
|
202
|
+
async getSchema (schemaName, options = {}) {
|
|
203
|
+
const schema = this.schemas[schemaName]
|
|
204
|
+
if (!schema) throw this.app.errors.MISSING_SCHEMA.setData({ schemaName })
|
|
205
|
+
return schema.build(options)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export default JsonSchemaModule
|
package/lib/Keywords.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { App } from 'adapt-authoring-core'
|
|
2
|
+
import bytes from 'bytes'
|
|
3
|
+
import ms from 'ms'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
/**
|
|
6
|
+
* Adds some useful schema keywords
|
|
7
|
+
* @memberof jsonschema
|
|
8
|
+
* @extends {AbstractModule}
|
|
9
|
+
*/
|
|
10
|
+
class Keywords {
|
|
11
|
+
static get all () {
|
|
12
|
+
const keywords = {
|
|
13
|
+
isBytes: function () {
|
|
14
|
+
return (value, { parentData, parentDataProperty }) => {
|
|
15
|
+
try {
|
|
16
|
+
parentData[parentDataProperty] = bytes.parse(value)
|
|
17
|
+
return true
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
isDate: function () {
|
|
24
|
+
return (value, { parentData, parentDataProperty }) => {
|
|
25
|
+
try {
|
|
26
|
+
parentData[parentDataProperty] = new Date(value)
|
|
27
|
+
return true
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
isDirectory: function () {
|
|
34
|
+
const doReplace = value => {
|
|
35
|
+
const app = App.instance
|
|
36
|
+
return [
|
|
37
|
+
['$ROOT', app.rootDir],
|
|
38
|
+
['$DATA', app.getConfig('dataDir')],
|
|
39
|
+
['$TEMP', app.getConfig('tempDir')]
|
|
40
|
+
].reduce((m, [k, v]) => {
|
|
41
|
+
return m.startsWith(k) ? path.resolve(v, m.replace(k, '').slice(1)) : m
|
|
42
|
+
}, value)
|
|
43
|
+
}
|
|
44
|
+
return (value, { parentData, parentDataProperty }) => {
|
|
45
|
+
try {
|
|
46
|
+
parentData[parentDataProperty] = doReplace(value)
|
|
47
|
+
} catch (e) {}
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
isTimeMs: function () {
|
|
52
|
+
return (value, { parentData, parentDataProperty }) => {
|
|
53
|
+
try {
|
|
54
|
+
parentData[parentDataProperty] = ms(value)
|
|
55
|
+
return true
|
|
56
|
+
} catch (e) {
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return Object.entries(keywords).map(([keyword, compile]) => {
|
|
63
|
+
return {
|
|
64
|
+
keyword,
|
|
65
|
+
type: 'string',
|
|
66
|
+
modifying: true,
|
|
67
|
+
schemaType: 'boolean',
|
|
68
|
+
compile
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default Keywords
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
a: ['class', 'href', 'target', 'title'],
|
|
3
|
+
abbr: ['title'],
|
|
4
|
+
address: [],
|
|
5
|
+
area: ['alt', 'coords', 'href', 'shape'],
|
|
6
|
+
article: [],
|
|
7
|
+
aside: ['aria-hidden', 'class', 'role'],
|
|
8
|
+
audio: [
|
|
9
|
+
'autoplay',
|
|
10
|
+
'controls',
|
|
11
|
+
'crossorigin',
|
|
12
|
+
'loop',
|
|
13
|
+
'muted',
|
|
14
|
+
'preload',
|
|
15
|
+
'src'
|
|
16
|
+
],
|
|
17
|
+
b: [],
|
|
18
|
+
bdi: ['dir'],
|
|
19
|
+
bdo: ['dir'],
|
|
20
|
+
big: [],
|
|
21
|
+
blockquote: ['cite'],
|
|
22
|
+
br: [],
|
|
23
|
+
button: ['class'],
|
|
24
|
+
caption: [],
|
|
25
|
+
center: [],
|
|
26
|
+
cite: [],
|
|
27
|
+
code: [],
|
|
28
|
+
col: ['align', 'span', 'valign', 'width'],
|
|
29
|
+
colgroup: ['align', 'span', 'valign', 'width'],
|
|
30
|
+
data: [],
|
|
31
|
+
dd: [],
|
|
32
|
+
del: ['datetime'],
|
|
33
|
+
dfn: [],
|
|
34
|
+
details: ['open'],
|
|
35
|
+
div: [
|
|
36
|
+
'aria-describedby',
|
|
37
|
+
'aria-description',
|
|
38
|
+
'aria-label',
|
|
39
|
+
'aria-hidden',
|
|
40
|
+
'class',
|
|
41
|
+
'role',
|
|
42
|
+
'tabindex'
|
|
43
|
+
],
|
|
44
|
+
dl: [],
|
|
45
|
+
dt: [],
|
|
46
|
+
em: [],
|
|
47
|
+
figcaption: [],
|
|
48
|
+
figure: ['class'],
|
|
49
|
+
font: ['color', 'face', 'size'],
|
|
50
|
+
footer: [],
|
|
51
|
+
h1: ['class'],
|
|
52
|
+
h2: ['class'],
|
|
53
|
+
h3: ['class'],
|
|
54
|
+
h4: ['class'],
|
|
55
|
+
h5: ['class'],
|
|
56
|
+
h6: ['class'],
|
|
57
|
+
header: [],
|
|
58
|
+
hr: [],
|
|
59
|
+
i: [],
|
|
60
|
+
img: [
|
|
61
|
+
'alt',
|
|
62
|
+
'aria-hidden',
|
|
63
|
+
'aria-label',
|
|
64
|
+
'class',
|
|
65
|
+
'height',
|
|
66
|
+
'loading',
|
|
67
|
+
'src',
|
|
68
|
+
'title',
|
|
69
|
+
'width'
|
|
70
|
+
],
|
|
71
|
+
ins: ['datetime'],
|
|
72
|
+
kbd: [],
|
|
73
|
+
li: ['class'],
|
|
74
|
+
mark: [],
|
|
75
|
+
math: [],
|
|
76
|
+
mfrac: [],
|
|
77
|
+
mi: [],
|
|
78
|
+
mn: [],
|
|
79
|
+
mo: [],
|
|
80
|
+
mover: [],
|
|
81
|
+
mrow: [],
|
|
82
|
+
ms: [],
|
|
83
|
+
mspace: [],
|
|
84
|
+
msub: [],
|
|
85
|
+
msubsup: [],
|
|
86
|
+
msup: [],
|
|
87
|
+
mtext: [],
|
|
88
|
+
munder: [],
|
|
89
|
+
munderover: [],
|
|
90
|
+
nav: [],
|
|
91
|
+
ol: ['class'],
|
|
92
|
+
p: ['lang'],
|
|
93
|
+
pre: [],
|
|
94
|
+
q: [],
|
|
95
|
+
rp: [],
|
|
96
|
+
rt: [],
|
|
97
|
+
ruby: [],
|
|
98
|
+
s: [],
|
|
99
|
+
samp: [],
|
|
100
|
+
section: [],
|
|
101
|
+
small: [],
|
|
102
|
+
span: [
|
|
103
|
+
'aria-describedby',
|
|
104
|
+
'aria-description',
|
|
105
|
+
'aria-label',
|
|
106
|
+
'aria-hidden',
|
|
107
|
+
'class',
|
|
108
|
+
'role',
|
|
109
|
+
'tabindex'
|
|
110
|
+
],
|
|
111
|
+
sub: [],
|
|
112
|
+
summary: [],
|
|
113
|
+
sup: [],
|
|
114
|
+
strong: [],
|
|
115
|
+
strike: [],
|
|
116
|
+
table: ['align', 'border', 'width', 'valign'],
|
|
117
|
+
tbody: ['align', 'valign'],
|
|
118
|
+
td: ['align', 'colspan', 'rowspan', 'valign', 'width'],
|
|
119
|
+
tfoot: ['align', 'valign'],
|
|
120
|
+
th: ['align', 'colspan', 'rowspan', 'valign', 'width'],
|
|
121
|
+
thead: ['align', 'valign'],
|
|
122
|
+
time: [],
|
|
123
|
+
tr: ['align', 'rowspan', 'valign'],
|
|
124
|
+
tt: [],
|
|
125
|
+
u: [],
|
|
126
|
+
ul: ['class'],
|
|
127
|
+
var: [],
|
|
128
|
+
video: [
|
|
129
|
+
'autoplay',
|
|
130
|
+
'controls',
|
|
131
|
+
'crossorigin',
|
|
132
|
+
'loop',
|
|
133
|
+
'muted',
|
|
134
|
+
'playsinline',
|
|
135
|
+
'poster',
|
|
136
|
+
'preload',
|
|
137
|
+
'src',
|
|
138
|
+
'height',
|
|
139
|
+
'width'
|
|
140
|
+
],
|
|
141
|
+
wbr: []
|
|
142
|
+
}
|
package/lib/typedefs.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file exists to define the below types for documentation purposes.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Ajv JSON Schema validator
|
|
6
|
+
* @memberof jsonschema
|
|
7
|
+
* @external Ajv
|
|
8
|
+
* @see {@link https://ajv.js.org/api.html#ajv-constructor-and-methods}
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Ajv custom keyword definition
|
|
12
|
+
* @memberof jsonschema
|
|
13
|
+
* @external AjvKeyword
|
|
14
|
+
* @see {@link https://ajv.js.org/keywords.html}
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* @memberof jsonschema
|
|
18
|
+
* @typedef {Object} ApplyPatchProperties
|
|
19
|
+
* @property {Object} extendAnnotations Whether annotation properties should be overwitten by the patch
|
|
20
|
+
* @property {Object} strict Restricts patches to only merge/patch schemas
|
|
21
|
+
* @property {Object} overwriteProperties Whether existing properties should be overwritten by the patch schema
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* @memberof jsonschema
|
|
25
|
+
* @typedef {Object} LoadSchemaOptions
|
|
26
|
+
* @property {Boolean} applyExtensions Whether extension schemas are applied
|
|
27
|
+
* @property {function} extensionFilter Function to selectively apply schema extensions. Function should return a boolean to signify whether the extension should be applied
|
|
28
|
+
* @property {Boolean} useCache Whether cached should be returned
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* @memberof jsonschema
|
|
32
|
+
* @typedef {Object} RegisterSchemaOptions
|
|
33
|
+
* @property {Boolean} replace Will replace the existing schema if one exists
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* @memberof jsonschema
|
|
37
|
+
* @typedef {Object} SanitiseOptions
|
|
38
|
+
* @property {Boolean} isInternal Whether internal attributes should be filtered
|
|
39
|
+
* @property {Boolean} isReadOnly Whether read-only attributes should be filtered
|
|
40
|
+
* @property {Boolean} sanitiseHtml Whether HTML text should be filtered
|
|
41
|
+
* @property {Boolean} strict Whether to throw errors
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* @memberof jsonschema
|
|
45
|
+
* @typedef {Object} ValidateOptions
|
|
46
|
+
* @property {Boolean} useDefaults Whether to apply defaults
|
|
47
|
+
* @property {Boolean} ignoreRequired Whether to ignore missing required fields
|
|
48
|
+
*/
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adapt-authoring-jsonschema",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Module to add support for the JSON schema specification",
|
|
5
|
+
"homepage": "https://github.com/adapt-security/adapt-authoring-jsonschema",
|
|
6
|
+
"license": "GPL-3.0",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"at-schemacheck": "./bin/check.js"
|
|
11
|
+
},
|
|
12
|
+
"repository": "github:adapt-security/adapt-authoring-jsonschema",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"ajv": "^8.12.0",
|
|
15
|
+
"bytes": "^3.1.2",
|
|
16
|
+
"glob": "^11.0.0",
|
|
17
|
+
"lodash": "^4.17.21",
|
|
18
|
+
"ms": "^2.1.3",
|
|
19
|
+
"safe-regex": "2.1.1",
|
|
20
|
+
"xss": "^1.0.14"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"adapt-authoring-core": "github:adapt-security/adapt-authoring-core"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"eslint": "^9.12.0",
|
|
27
|
+
"standard": "^17.1.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$anchor": "base",
|
|
4
|
+
"description": "The base schema inherited by all other schemas",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"_id": {
|
|
8
|
+
"description": "Unique identifier",
|
|
9
|
+
"type": "string",
|
|
10
|
+
"isObjectId": true
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|