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
package/.eslintignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
node_modules
|
package/.eslintrc
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: File a bug report
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to fill out this bug report!
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: description
|
|
11
|
+
attributes:
|
|
12
|
+
label: What happened?
|
|
13
|
+
description: Please describe the issue
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: expected
|
|
18
|
+
attributes:
|
|
19
|
+
label: Expected behaviour
|
|
20
|
+
description: Tell us what should have happened
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: repro-steps
|
|
23
|
+
attributes:
|
|
24
|
+
label: Steps to reproduce
|
|
25
|
+
description: Tell us how to reproduce the issue
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
- type: input
|
|
29
|
+
id: aat-version
|
|
30
|
+
attributes:
|
|
31
|
+
label: Authoring tool version
|
|
32
|
+
description: What version of the Adapt authoring tool are you running?
|
|
33
|
+
validations:
|
|
34
|
+
required: true
|
|
35
|
+
- type: input
|
|
36
|
+
id: fw-version
|
|
37
|
+
attributes:
|
|
38
|
+
label: Framework version
|
|
39
|
+
description: What version of the Adapt framework are you running?
|
|
40
|
+
- type: dropdown
|
|
41
|
+
id: browsers
|
|
42
|
+
attributes:
|
|
43
|
+
label: What browsers are you seeing the problem on?
|
|
44
|
+
multiple: true
|
|
45
|
+
options:
|
|
46
|
+
- Firefox
|
|
47
|
+
- Chrome
|
|
48
|
+
- Safari
|
|
49
|
+
- Microsoft Edge
|
|
50
|
+
- type: textarea
|
|
51
|
+
id: logs
|
|
52
|
+
attributes:
|
|
53
|
+
label: Relevant log output
|
|
54
|
+
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
|
55
|
+
render: sh
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Request a new feature
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to request a new feature in the Adapt authoring tool! The Adapt team will consider all new feature requests, but unfortunately cannot commit to every one.
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: description
|
|
11
|
+
attributes:
|
|
12
|
+
label: Feature description
|
|
13
|
+
description: Please describe your feature request
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: checkboxes
|
|
17
|
+
id: contribute
|
|
18
|
+
attributes:
|
|
19
|
+
label: Can you work on this feature?
|
|
20
|
+
description: If you are able to commit your own time to work on this feature, it will greatly increase the liklihood of it being implemented by the core dev team. Otherwise, it will be triaged and prioritised alongside the core team's current priorities.
|
|
21
|
+
options:
|
|
22
|
+
- label: I can contribute
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "npm" # See documentation for possible values
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[//]: # (Please title your PR according to eslint commit conventions)
|
|
2
|
+
[//]: # (See https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-eslint#eslint-convention for details)
|
|
3
|
+
|
|
4
|
+
[//]: # (Add a link to the original issue)
|
|
5
|
+
|
|
6
|
+
[//]: # (Delete as appropriate)
|
|
7
|
+
### Fix
|
|
8
|
+
* A sentence describing each fix
|
|
9
|
+
|
|
10
|
+
### Update
|
|
11
|
+
* A sentence describing each udpate
|
|
12
|
+
|
|
13
|
+
### New
|
|
14
|
+
* A sentence describing each new feature
|
|
15
|
+
|
|
16
|
+
### Breaking
|
|
17
|
+
* A sentence describing each breaking change
|
|
18
|
+
|
|
19
|
+
[//]: # (List appropriate steps for testing if needed)
|
|
20
|
+
### Testing
|
|
21
|
+
1. Steps for testing
|
|
22
|
+
|
|
23
|
+
[//]: # (Mention any other dependencies)
|
|
24
|
+
|
|
25
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: Add labelled PRs to project
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [ labeled ]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
add-to-project:
|
|
9
|
+
if: ${{ github.event.label.name == 'dependencies' }}
|
|
10
|
+
name: Add to main project
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/add-to-project@v0.1.0
|
|
14
|
+
with:
|
|
15
|
+
project-url: https://github.com/orgs/adapt-security/projects/5
|
|
16
|
+
github-token: ${{ secrets.PROJECTS_SECRET }}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Add to main project
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issues:
|
|
5
|
+
types:
|
|
6
|
+
- opened
|
|
7
|
+
pull_request:
|
|
8
|
+
types:
|
|
9
|
+
- opened
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
add-to-project:
|
|
13
|
+
name: Add to main project
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/add-to-project@v0.1.0
|
|
17
|
+
with:
|
|
18
|
+
project-url: https://github.com/orgs/adapt-security/projects/5
|
|
19
|
+
github-token: ${{ secrets.PROJECTS_SECRET }}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"essentialType": "schema",
|
|
3
|
+
"documentation": {
|
|
4
|
+
"enable": true,
|
|
5
|
+
"manualPlugins": ["docs/plugins/schemas-reference.js"],
|
|
6
|
+
"manualPages": {
|
|
7
|
+
"schema-examples.md": "reference",
|
|
8
|
+
"schemas-introduction.md": "basics",
|
|
9
|
+
"schemas-reference.md": "reference",
|
|
10
|
+
"writing-a-schema.md": "basics"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
package/bin/check.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Checks for duplicate schema properties
|
|
4
|
+
*/
|
|
5
|
+
import { App } from 'adapt-authoring-core'
|
|
6
|
+
|
|
7
|
+
process.env.NODE_ENV = 'production'
|
|
8
|
+
process.env.ADAPT_AUTHORING_LOGGER__mute = 'true'
|
|
9
|
+
|
|
10
|
+
let app
|
|
11
|
+
|
|
12
|
+
async function check () {
|
|
13
|
+
console.log('Checking for duplicate schema definitions.\n')
|
|
14
|
+
app = await App.instance.onReady()
|
|
15
|
+
const schema = await app.waitForModule('jsonschema')
|
|
16
|
+
|
|
17
|
+
await Promise.allSettled(Object.keys(schema.schemaPaths).map(async s => {
|
|
18
|
+
const usedKeys = {}
|
|
19
|
+
const hierarchy = await schema.loadSchemaHierarchy(s)
|
|
20
|
+
await Promise.all(hierarchy.map(s => checkSchema(s, usedKeys)))
|
|
21
|
+
const duplicates = Object.entries(usedKeys).filter(([key, uses]) => uses.length > 1)
|
|
22
|
+
|
|
23
|
+
if (duplicates.length) {
|
|
24
|
+
console.log(`Schema '${s}' contains duplicate definitions for the following properties:`)
|
|
25
|
+
duplicates.forEach(([prop, schemas]) => console.log(` - ${prop}: ${schemas}`))
|
|
26
|
+
console.log('')
|
|
27
|
+
process.exitCode = 1
|
|
28
|
+
}
|
|
29
|
+
}))
|
|
30
|
+
if (process.exitCode !== 1) console.log('No duplicates found.')
|
|
31
|
+
process.exit()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function checkSchema (schema, usedKeys) {
|
|
35
|
+
const props = schema.properties ?? schema?.$patch?.with?.properties ?? schema?.$merge?.with?.properties
|
|
36
|
+
Object.keys(props).forEach(p => {
|
|
37
|
+
if (p === '_globals') return
|
|
38
|
+
if (!usedKeys[p]) usedKeys[p] = []
|
|
39
|
+
usedKeys[p].push(schema.$anchor)
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
check()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"enableCache": {
|
|
6
|
+
"description": "Whether schema data should be cached",
|
|
7
|
+
"type": "boolean",
|
|
8
|
+
"default": true
|
|
9
|
+
},
|
|
10
|
+
"formatOverrides": {
|
|
11
|
+
"description": "Custom RegExp overrides for Ajv string formats",
|
|
12
|
+
"type": "object",
|
|
13
|
+
"default": {}
|
|
14
|
+
},
|
|
15
|
+
"xssWhitelist": {
|
|
16
|
+
"description": "Attributes which should be whitelisted when run through the XSS sanitiser.",
|
|
17
|
+
"type": "object",
|
|
18
|
+
"default": {}
|
|
19
|
+
},
|
|
20
|
+
"xssWhitelistOverride": {
|
|
21
|
+
"description": "If set to false, the xssWhitelist value will EXTEND the default XSS whitelist. If set to true, it will REPLACE it.",
|
|
22
|
+
"type": "boolean",
|
|
23
|
+
"default": false
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export default class SchemasReference {
|
|
2
|
+
constructor(app, config, dir, utils) {
|
|
3
|
+
this.app = app;
|
|
4
|
+
this.utils = utils;
|
|
5
|
+
}
|
|
6
|
+
async run() {
|
|
7
|
+
this.schemas = await this.loadSchemas();
|
|
8
|
+
this.manualFile = 'schemas-reference.md';
|
|
9
|
+
this.contents = Object.keys(this.schemas);
|
|
10
|
+
this.replace = { 'LIST': this.generateList() };
|
|
11
|
+
}
|
|
12
|
+
async loadSchemas() {
|
|
13
|
+
const schema = await this.app.waitForModule('jsonschema');
|
|
14
|
+
return Object.keys(schema.schemas)
|
|
15
|
+
.sort((a, b) => a.localeCompare(b))
|
|
16
|
+
.reduce((schemas, s) => Object.assign(schemas, { [s]: schema.schemas[s].raw }), {});
|
|
17
|
+
}
|
|
18
|
+
generateList() {
|
|
19
|
+
return Object.entries(this.schemas).reduce((output, [dep, schema]) => {
|
|
20
|
+
return `${output}<h3 id="${dep.toLowerCase()}" class="dep">${dep}</h3>
|
|
21
|
+
|
|
22
|
+
${this.schemaToMd(schema)}
|
|
23
|
+
|
|
24
|
+
`;
|
|
25
|
+
}, '');
|
|
26
|
+
}
|
|
27
|
+
schemaToMd(schema) {
|
|
28
|
+
let output = '';
|
|
29
|
+
if(schema.description) {
|
|
30
|
+
output += `<div class="desc">${schema.description}</div>\n\n`;
|
|
31
|
+
}
|
|
32
|
+
let s;
|
|
33
|
+
if(schema.properties) {
|
|
34
|
+
s = schema;
|
|
35
|
+
} else if(schema.$patch) {
|
|
36
|
+
s = schema.$patch.with;
|
|
37
|
+
const ref = schema.$patch.source.$ref;
|
|
38
|
+
output += `<div class="extension">Patches <a href="#/schemas-reference?id=${ref}">${ref}</a></div>`;
|
|
39
|
+
} else if(schema.$merge) {
|
|
40
|
+
s = schema.$merge.with;
|
|
41
|
+
const ref = schema.$merge?.source?.$ref;
|
|
42
|
+
output += `<div class="extension">${ref ? `Merges with <a href="#/schemas-reference?id=${ref}">${ref}</a>` : 'This is a merge schema'}</div>\n\n`;
|
|
43
|
+
}
|
|
44
|
+
const { properties, required } = s;
|
|
45
|
+
|
|
46
|
+
if(!properties) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if(required) {
|
|
50
|
+
output += `<div class="required">Fields in bold are required.</div>\n\n`;
|
|
51
|
+
}
|
|
52
|
+
const table = `<tr><th>Attribute</th><th>Type</th><th>Default</th><th>Description</th></tr>${this.tableRowsFromProps(properties, required)}`;
|
|
53
|
+
return `${output}<table class="schema">${table}</table>`;
|
|
54
|
+
}
|
|
55
|
+
tableRowsFromProps(properties, required = [], parent) {
|
|
56
|
+
return Object.entries(properties).reduce((output, [attr, config]) => {
|
|
57
|
+
const attrKey = (parent ? parent + '.' : '') + attr;
|
|
58
|
+
output += `<tr class="${config.default === undefined && required && required.includes(attr) ? 'required' : ''}">\n`;
|
|
59
|
+
output += `<td>${attrKey}</td>\n`;
|
|
60
|
+
output += `<td>${config.type}</td>\n`;
|
|
61
|
+
output += `<td>${config.default !== undefined ? this.defaultToMd(config.default) : ''}</td>\n`;
|
|
62
|
+
output += `<td>${config.description || ' '}</td>\n`;
|
|
63
|
+
output += `</tr>\n`;
|
|
64
|
+
if(config.properties) output += this.tableRowsFromProps(config.properties, config.required, attrKey);
|
|
65
|
+
return output;
|
|
66
|
+
}, '');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns a string formatted nicely for markdown
|
|
70
|
+
*/
|
|
71
|
+
defaultToMd(val) {
|
|
72
|
+
return `<pre>${JSON.stringify(val)}</pre>`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Schema examples
|
|
2
|
+
|
|
3
|
+
This page presents some example schema definitions (along with their UI representation) which may be useful in defining your own schemas.
|
|
4
|
+
|
|
5
|
+
## Quick navigation
|
|
6
|
+
- [String](#string)
|
|
7
|
+
- [String with text area](#string-with-text-area)
|
|
8
|
+
- [Number](#number)
|
|
9
|
+
- [Boolean with checkbox](#boolean-with-checkbox)
|
|
10
|
+
- [Image](#image)
|
|
11
|
+
- [Select](#select)
|
|
12
|
+
- [Object](#object)
|
|
13
|
+
- [Array](#array)
|
|
14
|
+
|
|
15
|
+
## String
|
|
16
|
+
|
|
17
|
+
> Simple string values do not need custom `_backboneForms` configuration.
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
"title": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"title": "Title",
|
|
23
|
+
"default": "Default title",
|
|
24
|
+
"_adapt": {
|
|
25
|
+
"translatable": true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
<img width="815" alt="Screenshot 2023-01-16 at 17 06 30" src="https://user-images.githubusercontent.com/11569678/212891159-e73fbe91-0169-429e-86c7-3f8231617b3b.png">
|
|
31
|
+
|
|
32
|
+
## String with text area
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
"body": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"title": "Body",
|
|
38
|
+
"default": "",
|
|
39
|
+
"_adapt": {
|
|
40
|
+
"translatable": true
|
|
41
|
+
},
|
|
42
|
+
"_backboneForms": "TextArea"
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
<img width="820" alt="Screenshot 2023-01-16 at 17 07 11" src="https://user-images.githubusercontent.com/11569678/212891179-f7477a54-3be5-4c39-aa60-7df67d86b7d2.png">
|
|
47
|
+
|
|
48
|
+
## Number
|
|
49
|
+
|
|
50
|
+
> Number values do not need custom `_backboneForms` configuration.
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
"_left": {
|
|
54
|
+
"type": "number",
|
|
55
|
+
"title": "Pin horizontal position (%)",
|
|
56
|
+
"description": "",
|
|
57
|
+
"default": 0
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
<img width="484" alt="Screenshot 2023-01-16 at 17 10 50" src="https://user-images.githubusercontent.com/11569678/212891200-f9968fe2-8882-4248-8bb2-d6b2f8151e56.png">
|
|
62
|
+
|
|
63
|
+
## Boolean with checkbox
|
|
64
|
+
|
|
65
|
+
> Boolean values do not need custom `_backboneForms` configuration.
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
"_isMobileTextBelowImage": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"title": "Move text area below image on mobile",
|
|
71
|
+
"description": "If enabled, on mobile, the text area drops below the image instead of being behind the strapline button",
|
|
72
|
+
"default": false
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
<img width="336" alt="Screenshot 2023-01-16 at 17 29 09" src="https://user-images.githubusercontent.com/11569678/212891377-4c3e130d-5f2a-4de5-b1e2-b1747ed2da0e.png">
|
|
77
|
+
|
|
78
|
+
## Image
|
|
79
|
+
|
|
80
|
+
In addition to the `type`, an asset sub-schema can define the type of the asset using the `media` property (see [this page](/schemas-introduction#custom-backbone-forms-properties) for more information).
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
"src": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"isObjectId": true,
|
|
86
|
+
"title": "Source",
|
|
87
|
+
"description": "This is the image that appears behind the pins",
|
|
88
|
+
"_backboneForms": {
|
|
89
|
+
"type": "Asset",
|
|
90
|
+
"media": "image"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
<img width="331" alt="Screenshot 2023-01-16 at 17 29 41" src="https://user-images.githubusercontent.com/11569678/212891422-c240c248-1bfd-4c2d-af63-a01aa281ba45.png">
|
|
96
|
+
|
|
97
|
+
## Select
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
"_setCompletionOn": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"title": "Completion criteria",
|
|
103
|
+
"description": "Whether completion is based on the learner having viewed all the narrative items - or just having viewed the component",
|
|
104
|
+
"default": "allItems",
|
|
105
|
+
"enum": [
|
|
106
|
+
"inview",
|
|
107
|
+
"allItems"
|
|
108
|
+
],
|
|
109
|
+
"_backboneForms": "Select"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
<img width="178" alt="Screenshot 2023-01-16 at 17 31 00" src="https://user-images.githubusercontent.com/11569678/212891453-5c482ea5-ef4f-425f-9756-cdb5b71d7e69.png">
|
|
114
|
+
|
|
115
|
+
## Object
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
"_graphic": {
|
|
119
|
+
"type": "object",
|
|
120
|
+
"title": "Graphic",
|
|
121
|
+
"default": {},
|
|
122
|
+
"properties": {
|
|
123
|
+
...omitted for brevity
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
<img width="485" alt="Screenshot 2023-01-16 at 17 33 08" src="https://user-images.githubusercontent.com/11569678/212891476-fab8198d-2dca-4ce5-af0b-4f07729780f4.png">
|
|
129
|
+
|
|
130
|
+
## Array
|
|
131
|
+
|
|
132
|
+
The items value is its own schema, and can take any of the standard types.
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
"_items": {
|
|
136
|
+
"type": "array",
|
|
137
|
+
"title": "Items",
|
|
138
|
+
"items": {
|
|
139
|
+
...
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
<img width="79" alt="Screenshot 2023-01-16 at 17 33 43" src="https://user-images.githubusercontent.com/11569678/212891491-b6102f17-7631-4ef3-b3cc-1c0dadfd3522.png">
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Introduction to schemas
|
|
2
|
+
|
|
3
|
+
The Adapt authoring tool uses the JSON Schema specification (draft 2020-12) to define its data schemas. This page will give you a brief explanation of why we use JSON schema.
|
|
4
|
+
|
|
5
|
+
## What is a schema?
|
|
6
|
+
|
|
7
|
+
At its most basic level, a schema is a 'blueprint' which is applied to information coming into the application.
|
|
8
|
+
|
|
9
|
+
As with architectural blueprints, a database schema defines how data should be structured and named, as well as other expectations such as the specific 'type' of the data (e.g. strings, numbers) as well as other restrictions (e.g. a fixed length for strings).
|
|
10
|
+
|
|
11
|
+
## Why use a schema?
|
|
12
|
+
|
|
13
|
+
Schemas are **MASSIVELY** useful because they set the expectations for data moving into and out of an application. This benefits third-parties because it makes it easier to design interactions with the application, and it benefits the application itself because it can assume that data entering from external sources is in an expected and valid format.
|
|
14
|
+
|
|
15
|
+
> **Note**: schemas only become useful when a 'validation' process is used, which compares data to the schema which defines that data. Without validation, we have no idea whether the data is safe to use or not.
|
|
16
|
+
|
|
17
|
+
## Why JSON Schemas?
|
|
18
|
+
_**TLDR;** JSON just 'works' with Javascript._
|
|
19
|
+
|
|
20
|
+
The JSON Schema specification is a schema spec based on Javascript Object Notation (JSON) and was designed specifically for annotating and validating JSON documents, which are the standard for data representation in Javascript code (and therefore Node.js). We also currently use MongoDB as our database which uses JSON-like documents.
|
|
21
|
+
|
|
22
|
+
Additionally, the JSON Schema specification has matured to a point where it is incredibly well supported by a host of third-party libraries from data validators to UI form renderers.
|
|
23
|
+
|
|
24
|
+
## Defining a schema
|
|
25
|
+
|
|
26
|
+
When defining a schema, you need to think about the kind of data you need, and how that data is best structured to make it easy to work with.
|
|
27
|
+
|
|
28
|
+
### Data types
|
|
29
|
+
|
|
30
|
+
JSON uses the following types:
|
|
31
|
+
- **object**: `{ "a": 1, "b": 2 }`
|
|
32
|
+
- **array**: `[1,2,3]`
|
|
33
|
+
- **number**: `369`
|
|
34
|
+
- **string**: `"Hello world"`
|
|
35
|
+
- **boolean**: `true`/`false`
|
|
36
|
+
- **null**: `null`
|
|
37
|
+
|
|
38
|
+
Combined, these types allow a huge amount of flexibility in the way that you want to define your data.
|
|
39
|
+
|
|
40
|
+
e.g.
|
|
41
|
+
```
|
|
42
|
+
{
|
|
43
|
+
"$anchor": "example-schema",
|
|
44
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
45
|
+
"type": "object",
|
|
46
|
+
"required": ["myRequiredAttribute"],
|
|
47
|
+
"properties": {
|
|
48
|
+
"myRequiredAttribute": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
},
|
|
51
|
+
"aStringAttribute": {
|
|
52
|
+
"type": "number",
|
|
53
|
+
"default": 12345
|
|
54
|
+
},
|
|
55
|
+
"aStringAttributeWithRestrictedValues": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"default": "false",
|
|
58
|
+
"enum": ["false", "soft", "hard"],
|
|
59
|
+
},
|
|
60
|
+
"nestedObjectAttribute": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"default": {},
|
|
63
|
+
"properties": {
|
|
64
|
+
"nestedProperty": {
|
|
65
|
+
"type": "boolean",
|
|
66
|
+
"default": true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> For more in-depth information on JSON schemas, the [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/) ebook is a great place to start.
|
|
75
|
+
|
|
76
|
+
## Next steps
|
|
77
|
+
|
|
78
|
+
When you're ready to start writing your own schemas, check out [this page](/writing-a-schema).
|