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 ADDED
@@ -0,0 +1 @@
1
+ node_modules
package/.eslintrc ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "env": {
3
+ "browser": false,
4
+ "node": true,
5
+ "commonjs": false,
6
+ "es2020": true
7
+ },
8
+ "extends": [
9
+ "standard"
10
+ ],
11
+ "parserOptions": {
12
+ "ecmaVersion": 2020
13
+ }
14
+ }
@@ -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,7 @@
1
+ # Schemas reference
2
+
3
+ This page documents all schemas defined in the authoring tool core bundle. Where relevant, any schema inheritance is noted, along with which fields are required.
4
+
5
+ {{{TABLE_OF_CONTENTS}}}
6
+
7
+ {{{LIST}}}
@@ -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).