adapt-authoring-docs 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/.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/.github/workflows/releases.yml +32 -0
- package/.github/workflows/standardjs.yml +13 -0
- package/adapt-authoring.json +11 -0
- package/assets/bg.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/logo-outline-black.png +0 -0
- package/assets/logo-outline-colour.png +0 -0
- package/assets/logo.png +0 -0
- package/bin/docgen.js +102 -0
- package/bin/docserve.js +51 -0
- package/conf/config.schema.json +40 -0
- package/docs/building-docs.md +21 -0
- package/docs/custom-documentation-plugins.md +41 -0
- package/docs/writing-documentation.md +55 -0
- package/docsify/DocsifyPluginWrapper.js +67 -0
- package/docsify/docsify.js +105 -0
- package/docsify/index.html +33 -0
- package/docsify/js/adapt.js +32 -0
- package/docsify/styles/adapt.css +230 -0
- package/jsdoc3/jsdoc3.js +106 -0
- package/jsdoc3/scripts/adapt.js +18 -0
- package/jsdoc3/styles/adapt.css +144 -0
- package/package.json +64 -0
- package/root/.nojekyll +0 -0
- package/root/index.html +116 -0
- package/swagger/index.html +28 -0
- package/swagger/styles/adapt.css +111 -0
- package/swagger/swagger.js +96 -0
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "adapt-authoring-docs",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Tools for auto-generating documentation for the Adapt authoring tool",
|
|
5
|
+
"homepage": "https://github.com/adapt-security/adapt-authoring-docs",
|
|
6
|
+
"license": "GPL-3.0",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"at-docgen": "./bin/docgen.js",
|
|
10
|
+
"at-docserve": "./bin/docserve.js"
|
|
11
|
+
},
|
|
12
|
+
"repository": "github:adapt-security/adapt-authoring-docs",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"comment-parser": "^1.4.1",
|
|
15
|
+
"docdash": "^2.0.2",
|
|
16
|
+
"docsify-cli": "^4.4.4",
|
|
17
|
+
"fs-extra": "^11.2.0",
|
|
18
|
+
"glob": "^11.0.0",
|
|
19
|
+
"http-server": "^14.1.1",
|
|
20
|
+
"jsdoc": "^4.0.3",
|
|
21
|
+
"swagger-ui": "^5.17.14"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"adapt-authoring-core": "github:adapt-security/adapt-authoring-core"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
28
|
+
"@semantic-release/git": "^10.0.1",
|
|
29
|
+
"@semantic-release/github": "^12.0.2",
|
|
30
|
+
"@semantic-release/npm": "^13.1.2",
|
|
31
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
32
|
+
"conventional-changelog-eslint": "^6.0.0",
|
|
33
|
+
"semantic-release": "^25.0.2",
|
|
34
|
+
"semantic-release-replace-plugin": "^1.2.7",
|
|
35
|
+
"standard": "^17.1.0"
|
|
36
|
+
},
|
|
37
|
+
"release": {
|
|
38
|
+
"plugins": [
|
|
39
|
+
[
|
|
40
|
+
"@semantic-release/commit-analyzer",
|
|
41
|
+
{
|
|
42
|
+
"preset": "eslint"
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
"@semantic-release/release-notes-generator",
|
|
47
|
+
{
|
|
48
|
+
"preset": "eslint"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"@semantic-release/npm",
|
|
52
|
+
"@semantic-release/github",
|
|
53
|
+
[
|
|
54
|
+
"@semantic-release/git",
|
|
55
|
+
{
|
|
56
|
+
"assets": [
|
|
57
|
+
"package.json"
|
|
58
|
+
],
|
|
59
|
+
"message": "Chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
package/root/.nojekyll
ADDED
|
File without changes
|
package/root/index.html
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<link rel="icon" href="assets/favicon.png" sizes="any">
|
|
8
|
+
<title>Documentation - Adapt authoring tool</title>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div class="container"><img src="assets/logo.png" /></div>
|
|
12
|
+
<h1>Adapt authoring tool</h1>
|
|
13
|
+
<h2>Documentation</h2>
|
|
14
|
+
<div class="link-container">
|
|
15
|
+
<a class="big" href="manual">Developer guides</a>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="link-container">
|
|
18
|
+
<a href="rest">REST API Reference</a>
|
|
19
|
+
<a href="backend">Server Code Reference</a>
|
|
20
|
+
<a href="frontend">UI Code Reference</a>
|
|
21
|
+
</div>
|
|
22
|
+
<div id="update-age" class="hide">Docs updated <span id="age"></span> ago.</div>
|
|
23
|
+
</body>
|
|
24
|
+
<style>
|
|
25
|
+
@import url(https://fonts.googleapis.com/css?family=Open+Sans:300,400,700|Roboto+Mono);
|
|
26
|
+
body {
|
|
27
|
+
background: linear-gradient(to left bottom, #263944 0%,#0096bb 100%) !important;
|
|
28
|
+
font-family: 'Open Sans', sans-serif;
|
|
29
|
+
color: white;
|
|
30
|
+
width: 100vw;
|
|
31
|
+
height: 100vh;
|
|
32
|
+
text-align: center;
|
|
33
|
+
margin-top: 15vh;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
}
|
|
36
|
+
h1 {
|
|
37
|
+
font-size: 2.5rem;
|
|
38
|
+
font-weight: 300;
|
|
39
|
+
}
|
|
40
|
+
h2 {
|
|
41
|
+
font-size: 5em;
|
|
42
|
+
font-weight: 300;
|
|
43
|
+
}
|
|
44
|
+
.link-container {
|
|
45
|
+
margin-bottom: 2rem;
|
|
46
|
+
}
|
|
47
|
+
a {
|
|
48
|
+
border-radius: 3rem;
|
|
49
|
+
border: 1px solid white;
|
|
50
|
+
box-sizing: border-box;
|
|
51
|
+
color: white;
|
|
52
|
+
display: inline-block;
|
|
53
|
+
font-size: 1.1rem;
|
|
54
|
+
margin: .5rem 1rem;
|
|
55
|
+
padding: .75em 2rem;
|
|
56
|
+
text-decoration: none;
|
|
57
|
+
transition: all .15s ease;
|
|
58
|
+
}
|
|
59
|
+
a.big {
|
|
60
|
+
font-size: 1.4rem;;
|
|
61
|
+
}
|
|
62
|
+
a:hover {
|
|
63
|
+
background: white;
|
|
64
|
+
color: #14647b;
|
|
65
|
+
}
|
|
66
|
+
#update-age {
|
|
67
|
+
position: fixed;
|
|
68
|
+
padding: 20px;
|
|
69
|
+
text-align: center;
|
|
70
|
+
width: 100%;
|
|
71
|
+
bottom: 0;
|
|
72
|
+
font-size: 90%;
|
|
73
|
+
opacity: 1;
|
|
74
|
+
transition: opacity 0.3s;
|
|
75
|
+
}
|
|
76
|
+
#update-age.hide {
|
|
77
|
+
opacity: 0;
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
80
|
+
<script>
|
|
81
|
+
async function getUpdateDate() {
|
|
82
|
+
try {
|
|
83
|
+
const res = await fetch('https://api.github.com/repos/adapt-security/adapt-authoring-documentation/commits/master');
|
|
84
|
+
if(res.status > 299) {
|
|
85
|
+
throw new Error(res.statusText);
|
|
86
|
+
}
|
|
87
|
+
const data = await res.json();
|
|
88
|
+
const age = getAge(data.commit.committer.date);
|
|
89
|
+
document.getElementById('age').innerHTML = `${age.diff} ${age.unit}`;
|
|
90
|
+
document.getElementById('update-age').classList.remove("hide");
|
|
91
|
+
} catch(e) {
|
|
92
|
+
console.error(e);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function getAge(timestamp) {
|
|
96
|
+
const diffMs = new Date() - new Date(timestamp);
|
|
97
|
+
let divider = 1000;
|
|
98
|
+
const units = [
|
|
99
|
+
{ duration: 1, unit: 'second' },
|
|
100
|
+
{ duration: 60, unit: 'minute' },
|
|
101
|
+
{ duration: 60, unit: 'hour' },
|
|
102
|
+
{ duration: 24, unit: 'day' },
|
|
103
|
+
{ duration: 30, unit: 'week' },
|
|
104
|
+
{ duration: 12, unit: 'month' }
|
|
105
|
+
];
|
|
106
|
+
return units.reduce((memo, data) => {
|
|
107
|
+
divider *= data.duration;
|
|
108
|
+
data.rawDiff = diffMs/divider;
|
|
109
|
+
data.diff = Math.round(data.rawDiff);
|
|
110
|
+
if(data.diff > 1) data.unit += 's';
|
|
111
|
+
return data.rawDiff > 1 ? data : memo;
|
|
112
|
+
}, {});
|
|
113
|
+
}
|
|
114
|
+
getUpdateDate();
|
|
115
|
+
</script>
|
|
116
|
+
</html>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<head>
|
|
3
|
+
<meta charset="UTF-8">
|
|
4
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<link rel="icon" href="assets/favicon.png" sizes="any">
|
|
7
|
+
<script src="js/swagger-ui-bundle.js" crossorigin></script>
|
|
8
|
+
<script src="js/swagger-ui-standalone-preset.js" crossorigin></script>
|
|
9
|
+
<link rel="stylesheet" href="styles/swagger-ui.css" />
|
|
10
|
+
<link rel="stylesheet" href="styles/adapt.css">
|
|
11
|
+
</head>
|
|
12
|
+
<html>
|
|
13
|
+
<head>
|
|
14
|
+
<meta charset="UTF-8">
|
|
15
|
+
<title>Adapt authoring tool - REST API documentation</title>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<header>
|
|
19
|
+
<div class="container"><img src="assets/logo.png" /></div>
|
|
20
|
+
<h1>Adapt authoring tool</h1>
|
|
21
|
+
<h2>REST API Documentation</h2>
|
|
22
|
+
</header>
|
|
23
|
+
<div id="swagger"></div>
|
|
24
|
+
<script>
|
|
25
|
+
window.onload = () => SwaggerUIBundle({ url: 'api.json', dom_id: '#swagger' });
|
|
26
|
+
</script>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
@import url(https://fonts.googleapis.com/css?family=Open+Sans:300,400,700|Roboto+Mono);
|
|
2
|
+
|
|
3
|
+
body {
|
|
4
|
+
--default-font-family: 'Open Sans' !important;
|
|
5
|
+
--default-font-size: 13px;
|
|
6
|
+
--mono-font-family: 'Roboto Mono', monospace !important;
|
|
7
|
+
font-family: var(--default-font-family);
|
|
8
|
+
font-size: var(--default-font-size);
|
|
9
|
+
margin: 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
h1, h2, h3, h4, h5, h6,
|
|
13
|
+
h1 > a, h2 > a, h3 > a, h4 > a, h5 > a, h6 > a {
|
|
14
|
+
font-family: var(--default-font-family);
|
|
15
|
+
font-weight: 300 !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.main a,
|
|
19
|
+
.auth-wrapper,
|
|
20
|
+
.try-out {
|
|
21
|
+
display: none !important;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
header {
|
|
25
|
+
padding: 20px;
|
|
26
|
+
margin-bottom: 15px;
|
|
27
|
+
color: white;
|
|
28
|
+
text-align: center;
|
|
29
|
+
background: linear-gradient(to left bottom, #263944 0%,#0096bb 100%) !important;
|
|
30
|
+
}
|
|
31
|
+
header img {
|
|
32
|
+
height: 50px;
|
|
33
|
+
}
|
|
34
|
+
header h1 {
|
|
35
|
+
font-size: 200%;
|
|
36
|
+
margin: 10px;
|
|
37
|
+
}
|
|
38
|
+
header h2 {
|
|
39
|
+
font-size: initial;
|
|
40
|
+
margin: 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#swagger {
|
|
44
|
+
margin-bottom: 50px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.swagger-ui .wrapper {
|
|
48
|
+
max-width: 1000px;
|
|
49
|
+
}
|
|
50
|
+
/* hide schemas UI */
|
|
51
|
+
.swagger-ui .wrapper:last-child {
|
|
52
|
+
display: none;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.swagger-ui .info {
|
|
56
|
+
margin: 0 !important;
|
|
57
|
+
text-align: center;
|
|
58
|
+
}
|
|
59
|
+
.swagger-ui .info hgroup.main {
|
|
60
|
+
margin-bottom: 0;
|
|
61
|
+
}
|
|
62
|
+
.swagger-ui .info .title {
|
|
63
|
+
display: inline-block;
|
|
64
|
+
font-size: initial !important;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.swagger-ui .main small {
|
|
68
|
+
position: initial !important;
|
|
69
|
+
border-radius: 3px !important;
|
|
70
|
+
vertical-align: initial !important;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.swagger-ui .opblock-description-wrapper p,
|
|
74
|
+
.swagger-ui .opblock-external-docs-wrapper p,
|
|
75
|
+
.swagger-ui .opblock-title_normal p,
|
|
76
|
+
.swagger-ui .opblock opblock-summary-method,
|
|
77
|
+
.swagger-ui .opblock .opblock-summary-description,
|
|
78
|
+
.swagger-ui .parameter__name.required {
|
|
79
|
+
font-family: var(--default-font-family);
|
|
80
|
+
font-size: var(--default-font-size);
|
|
81
|
+
}
|
|
82
|
+
.swagger-ui .opblock-body pre.microlight {
|
|
83
|
+
padding: 15px !important;
|
|
84
|
+
font-size: 85%;
|
|
85
|
+
font-weight: normal;
|
|
86
|
+
white-space: nowrap;
|
|
87
|
+
overflow-y: scroll;
|
|
88
|
+
}
|
|
89
|
+
.swagger-ui .opblock-body select {
|
|
90
|
+
font-size: 90%;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.swagger-ui .opblock .opblock-summary-path {
|
|
94
|
+
font-size: var(--default-font-size);
|
|
95
|
+
font-weight: bold;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.swagger-ui .opblock .opblock-summary-description {
|
|
99
|
+
text-align: right;
|
|
100
|
+
margin-right: 15px;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.swagger-ui .opblock .opblock-description span {
|
|
104
|
+
background-color: #8121d9;
|
|
105
|
+
color: white;
|
|
106
|
+
padding: 3px 5px;
|
|
107
|
+
margin-left: 5px;
|
|
108
|
+
border-radius: 3px;
|
|
109
|
+
font-family: monospace;
|
|
110
|
+
font-size: 85%;
|
|
111
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { fileURLToPath } from 'url'
|
|
2
|
+
import fs from 'fs/promises'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
function resolvePath (relativePath) {
|
|
6
|
+
return fileURLToPath(new URL(relativePath, import.meta.url))
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
export default async function swagger (app, configs, outputdir) {
|
|
12
|
+
const server = await app.waitForModule('server')
|
|
13
|
+
await app.onReady()
|
|
14
|
+
const spec = {
|
|
15
|
+
openapi: '3.0.3',
|
|
16
|
+
info: { version: app.pkg.version },
|
|
17
|
+
components: { schemas: await generateSchemaSpec(app) },
|
|
18
|
+
paths: generatePathSpec(app, server.api)
|
|
19
|
+
}
|
|
20
|
+
// generate UI
|
|
21
|
+
const dir = path.resolve(outputdir, 'rest')
|
|
22
|
+
const cssDir = path.resolve(dir, 'styles')
|
|
23
|
+
const jsDir = path.resolve(dir, 'js')
|
|
24
|
+
const distDir = 'node_modules/swagger-ui/dist'
|
|
25
|
+
|
|
26
|
+
await fs.mkdir(dir)
|
|
27
|
+
await fs.mkdir(cssDir)
|
|
28
|
+
await fs.mkdir(jsDir)
|
|
29
|
+
|
|
30
|
+
await Promise.all([
|
|
31
|
+
fs.cp(resolvePath('./index.html'), path.resolve(dir, 'index.html')),
|
|
32
|
+
fs.cp(path.join(distDir, 'swagger-ui.css'), path.resolve(cssDir, 'swagger-ui.css')),
|
|
33
|
+
fs.cp(resolvePath('./styles/adapt.css'), path.resolve(cssDir, 'adapt.css')),
|
|
34
|
+
fs.cp(resolvePath('../assets'), path.resolve(dir, 'assets'), { recursive: true }),
|
|
35
|
+
fs.cp(path.join(distDir, 'swagger-ui-bundle.js'), path.resolve(jsDir, 'swagger-ui-bundle.js')),
|
|
36
|
+
fs.cp(path.join(distDir, 'swagger-ui-standalone-preset.js'), path.resolve(jsDir, 'swagger-ui-standalone-preset.js')),
|
|
37
|
+
fs.writeFile(path.resolve(dir, 'api.json'), JSON.stringify(spec, null, 2))
|
|
38
|
+
])
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function generateSchemaSpec (app) {
|
|
42
|
+
const jsonschema = await app.waitForModule('jsonschema')
|
|
43
|
+
const schemas = {}
|
|
44
|
+
await Promise.all(Object.keys(jsonschema.schemas).map(async s => {
|
|
45
|
+
schemas[s] = sanitiseSchema((await jsonschema.getSchema(s)).built)
|
|
46
|
+
}))
|
|
47
|
+
return schemas
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function sanitiseSchema (schema) {
|
|
51
|
+
const props = schema.properties ?? schema
|
|
52
|
+
for (const prop in props) {
|
|
53
|
+
const s = props[prop]
|
|
54
|
+
if (s.type === 'object') props[prop] = sanitiseSchema(s)
|
|
55
|
+
if (s.isInternal || s.isReadOnly) delete props[prop]
|
|
56
|
+
}
|
|
57
|
+
return schema
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function generatePathSpec (app, router, paths = {}) {
|
|
61
|
+
const perms = app.dependencyloader.instances['adapt-authoring-auth'].permissions.routes
|
|
62
|
+
router.routes.forEach(r => {
|
|
63
|
+
const parameters = r.route.split('/').filter(r => r.startsWith(':')).map(r => {
|
|
64
|
+
return {
|
|
65
|
+
name: r.replaceAll(/:|\?/g, ''),
|
|
66
|
+
in: 'path',
|
|
67
|
+
required: !r.endsWith('?')
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
const route = `${router.path}${r.route !== '/' ? r.route : ''}`
|
|
71
|
+
paths[route] = Object.keys(r.handlers).reduce((memo, method) => {
|
|
72
|
+
const meta = r.meta?.[method] || {}
|
|
73
|
+
const scopes = perms[method].find(p => route.match(p[0]))?.[1] || []
|
|
74
|
+
let description = r.internal ? 'ROUTE IS ONLY ACCESSIBLE FROM LOCALHOST.<br/><br/>' : ''
|
|
75
|
+
description += scopes.length
|
|
76
|
+
? `Required scopes: ${scopes.map(s => `<span>${s}</span>`).join(' ')}`
|
|
77
|
+
: 'Route requires no authentication'
|
|
78
|
+
|
|
79
|
+
if (meta.description) description += `<br/><br/>${meta.description}`
|
|
80
|
+
|
|
81
|
+
return Object.assign(memo, {
|
|
82
|
+
[method]: {
|
|
83
|
+
...meta,
|
|
84
|
+
tags: [router.path.split('/').slice(2).join(' ')],
|
|
85
|
+
description,
|
|
86
|
+
parameters: meta.parameters ? parameters.concat(meta.parameters) : parameters,
|
|
87
|
+
security: { roles: scopes }
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
}, {})
|
|
91
|
+
})
|
|
92
|
+
if (router.childRouters.length) {
|
|
93
|
+
router.childRouters.forEach(childRouter => generatePathSpec(app, childRouter, paths))
|
|
94
|
+
}
|
|
95
|
+
return Object.keys(paths).sort().reduce((m, k) => Object.assign(m, { [k]: paths[k] }), {})
|
|
96
|
+
}
|