@skriptfabrik/elements-cli 0.5.0 → 0.5.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/pull_request_template.md +7 -7
- package/.github/workflows/ci.yml +2 -2
- package/elements-cli.mjs +270 -265
- package/package.json +5 -5
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
## Describe your changes
|
|
2
2
|
|
|
3
|
-
-
|
|
4
|
-
-
|
|
5
|
-
-
|
|
3
|
+
- [ ] Bug fix (non-breaking change which fixes an issue)
|
|
4
|
+
- [ ] New feature (non-breaking change which adds functionality)
|
|
5
|
+
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
|
6
6
|
|
|
7
7
|
## Checklist before requesting a review
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
9
|
+
- [ ] I have included the ticket number of the issue at the beginning of the title of this pull request.
|
|
10
|
+
- [ ] I have updated the docs and/or specs to reflect this change.
|
|
11
|
+
- [ ] I have performed a self-review of my code.
|
|
12
|
+
- [ ] I have added thorough tests.
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -68,7 +68,7 @@ jobs:
|
|
|
68
68
|
|
|
69
69
|
- name: Build and Push latest Docker image
|
|
70
70
|
if: github.ref_name == 'main'
|
|
71
|
-
uses: docker/build-push-action@
|
|
71
|
+
uses: docker/build-push-action@v4
|
|
72
72
|
with:
|
|
73
73
|
build-args: |-
|
|
74
74
|
BUILDKIT_INLINE_CACHE=${{ env.DOCKER_BUILDKIT_INLINE_CACHE }}
|
|
@@ -90,7 +90,7 @@ jobs:
|
|
|
90
90
|
|
|
91
91
|
- name: Build and Push Docker image release version
|
|
92
92
|
if: github.ref_type == 'tag'
|
|
93
|
-
uses: docker/build-push-action@
|
|
93
|
+
uses: docker/build-push-action@v4
|
|
94
94
|
with:
|
|
95
95
|
build-args: |-
|
|
96
96
|
BUILDKIT_INLINE_CACHE=${{ env.DOCKER_BUILDKIT_INLINE_CACHE }}
|
package/elements-cli.mjs
CHANGED
|
@@ -28,209 +28,209 @@ const pkg = JSON.parse(await readFile(path.join(__dirname, 'package.json')));
|
|
|
28
28
|
// Argument defaults
|
|
29
29
|
|
|
30
30
|
const argd = {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
'base-path': process.env.ELEMENTS_BASE_PATH || process.env.BASE_PATH || '/',
|
|
32
|
+
'credentials-policy': process.env.ELEMENTS_CREDENTIALS_POLICY || process.env.CREDENTIALS_POLICY || 'omit',
|
|
33
|
+
hostname: process.env.ELEMENTS_HOSTNAME || 'localhost',
|
|
34
|
+
layout: process.env.ELEMENTS_LAYOUT || process.env.LAYOUT || 'sidebar',
|
|
35
|
+
logo: process.env.ELEMENTS_LOGO || process.env.LOGO,
|
|
36
|
+
port: parseInt(process.env.ELEMENTS_PORT || '8000'),
|
|
37
|
+
router: process.env.ELEMENTS_ROUTER || process.env.ROUTER || 'history',
|
|
38
|
+
style: process.env.ELEMENTS_STYLE || process.env.STYLE || 'flex: 1 0 0; overflow: hidden;',
|
|
39
|
+
title: process.env.ELEMENTS_TITLE || process.env.TITLE || 'My API Docs',
|
|
40
|
+
variable: (process.env.ELEMENTS_VARIABLE || process.env.VARIABLE || '').split('\n').map(variable => variable.trim()),
|
|
41
|
+
'virtual-host': process.env.ELEMENTS_VIRTUAL_HOST || 'localhost',
|
|
42
|
+
'virtual-port': process.env.ELEMENTS_VIRTUAL_PORT || '8000',
|
|
43
|
+
'working-dir': process.cwd(),
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
// Parse arguments
|
|
47
47
|
|
|
48
48
|
const argv = minimist(process.argv.slice(2), {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
boolean: ['c', 'f', 'h', 'n', 'p', 'v', 'w'],
|
|
50
|
+
alias: {
|
|
51
|
+
c: 'with-cors-proxy',
|
|
52
|
+
f: 'filter-internal',
|
|
53
|
+
h: 'help',
|
|
54
|
+
n: 'no-try-it',
|
|
55
|
+
p: 'poll',
|
|
56
|
+
v: 'version',
|
|
57
|
+
w: 'watch',
|
|
58
|
+
},
|
|
59
|
+
default: argd,
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
// Print version number
|
|
63
63
|
|
|
64
64
|
if (argv.version) {
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
console.log(pkg.version);
|
|
66
|
+
process.exit(0);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// Display help message
|
|
70
70
|
|
|
71
71
|
if (argv.help || argv._.length < 2 || !['export', 'preview'].includes(argv._[0])) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
72
|
+
if (argv._[0] === 'export') {
|
|
73
|
+
console.error(
|
|
74
|
+
`Elements CLI\n\n${chalk.yellow('Usage:')}\n%s\n\n${chalk.yellow('Arguments:')}\n%s\n\n${chalk.yellow('Options:')}\n%s\n\n${chalk.yellow('Examples:')}\n%s`,
|
|
75
|
+
` ${path.basename(process.argv[1])} export [options] <openapi_json>`,
|
|
76
|
+
` ${chalk.green('openapi_json')} The path or URL of the OpenAPI JSON file`,
|
|
77
|
+
[
|
|
78
|
+
` ${chalk.green(' --base-path=BASE_PATH')} Use the given base path ${chalk.yellow('[default: "' + argd['base-path'] + '"]')}`,
|
|
79
|
+
` ${chalk.green(' --credentials-policy=CREDENTIALS_POLICY')} Credentials policy for "Try It" feature: omit, include, same-origin ${chalk.yellow('[default: "' + argd['credentials-policy'] + '"]')}`,
|
|
80
|
+
` ${chalk.green(' --cors-proxy=CORS_PROXY')} Provide CORS proxy`,
|
|
81
|
+
` ${chalk.green('-f, --filter-internal')} Filter out any content which has been marked as internal with x-internal`,
|
|
82
|
+
` ${chalk.green('-h, --help')} Display this help message`,
|
|
83
|
+
` ${chalk.green(' --layout=LAYOUT')} Layout for Elements: sidebar, stacked ${chalk.yellow('[default: "' + argd.layout + '"]')}`,
|
|
84
|
+
` ${chalk.green(' --logo=LOGO')} URL of an image that will show as a small square logo next to the title`,
|
|
85
|
+
` ${chalk.green('-n --no-try-it')} Hide the "Try It" panel (the interactive API console)`,
|
|
86
|
+
` ${chalk.green(' --router=ROUTER')} Determines how navigation should work: history, hash, memory, static ${chalk.yellow('[default: "' + argd.router + '"]')}`,
|
|
87
|
+
` ${chalk.green(' --style=STYLE')} Additional style for Elements ${chalk.yellow('[default: "' + argd.style + '"]')}`,
|
|
88
|
+
` ${chalk.green(' --title=TITLE')} API docs title ${chalk.yellow('[default: "' + argd.title + '"]')}`,
|
|
89
|
+
` ${chalk.green(' --variable=VARIABLE')} Variable to be replaced in the OpenAPI document`,
|
|
90
|
+
` ${chalk.green('-v, --version')} Print version number`,
|
|
91
|
+
].join('\n'),
|
|
92
|
+
[
|
|
93
|
+
` Export rendered API docs based on local ${chalk.magenta('openapi.json')} path as ${chalk.magenta('index.html')}:`,
|
|
94
|
+
``,
|
|
95
|
+
` ${chalk.green(path.basename(process.argv[1]) + ' export openapi.json > index.html')}`,
|
|
96
|
+
``,
|
|
97
|
+
` Export rendered Swagger Petstore docs based on remote ${chalk.magenta('https://petstore.swagger.io/v2/swagger.json')} URL as ${chalk.magenta('index.html')}:`,
|
|
98
|
+
``,
|
|
99
|
+
` ${chalk.green(path.basename(process.argv[1]) + ' export --title="Swagger Petstore" https://petstore.swagger.io/v2/swagger.json > index.html')}`,
|
|
100
|
+
].join('\n'),
|
|
101
|
+
);
|
|
102
|
+
} else if (argv._[0] === 'preview') {
|
|
103
|
+
console.error(
|
|
104
|
+
`Elements CLI\n\n${chalk.yellow('Usage:')}\n%s\n\n${chalk.yellow('Arguments:')}\n%s\n\n${chalk.yellow('Options:')}\n%s\n\n${chalk.yellow('Examples:')}\n%s`,
|
|
105
|
+
` ${path.basename(process.argv[1])} preview [options] <openapi_json>`,
|
|
106
|
+
` ${chalk.green('openapi_json')} The path or URL of the OpenAPI JSON file`,
|
|
107
|
+
[
|
|
108
|
+
` ${chalk.green(' --base-path=BASE_PATH')} Use the given base path ${chalk.yellow('[default: "' + argd['base-path'] + '"]')}`,
|
|
109
|
+
` ${chalk.green(' --credentials-policy=CREDENTIALS_POLICY')} Credentials policy for "Try It" feature: omit, include, same-origin ${chalk.yellow('[default: "' + argd['credentials-policy'] + '"]')}`,
|
|
110
|
+
` ${chalk.green('-c --with-cors-proxy')} Enable CORS proxy capabilities`,
|
|
111
|
+
` ${chalk.green('-f, --filter-internal')} Filter out any content which has been marked as internal with x-internal`,
|
|
112
|
+
` ${chalk.green('-h, --help')} Display this help message`,
|
|
113
|
+
` ${chalk.green(' --hostname=HOSTNAME')} Server hostname ${chalk.yellow('[default: "' + argd.hostname + '"]')}`,
|
|
114
|
+
` ${chalk.green(' --layout=LAYOUT')} Layout for Elements: sidebar, stacked ${chalk.yellow('[default: "' + argd.layout + '"]')}`,
|
|
115
|
+
` ${chalk.green(' --logo=LOGO')} URL of an image that will show as a small square logo next to the title`,
|
|
116
|
+
` ${chalk.green('-n --no-try-it')} Hide the "Try It" panel (the interactive API console)`,
|
|
117
|
+
` ${chalk.green('-p, --poll')} Use polling instead of file system events`,
|
|
118
|
+
` ${chalk.green(' --port=PORT')} Server port ${chalk.yellow('[default: ' + argd.port + ']')}`,
|
|
119
|
+
` ${chalk.green(' --router=ROUTER')} Determines how navigation should work: history, hash, memory, static ${chalk.yellow('[default: "' + argd.router + '"]')}`,
|
|
120
|
+
` ${chalk.green(' --style=STYLE')} Additional style for Elements ${chalk.yellow('[default: "' + argd.style + '"]')}`,
|
|
121
|
+
` ${chalk.green(' --title=TITLE')} API docs title ${chalk.yellow('[default: "' + argd.title + '"]')}`,
|
|
122
|
+
` ${chalk.green(' --variable=VARIABLE')} Variable to be replaced in the OpenAPI document`,
|
|
123
|
+
` ${chalk.green('-v, --version')} Print version number`,
|
|
124
|
+
` ${chalk.green('-w --watch')} Watch for changes and reload (only for local files)`,
|
|
125
|
+
` ${chalk.green(' --virtual-host=VIRTUAL_HOST')} Reported hostname ${chalk.yellow('[default: ' + argd['virtual-host'] + ']')}`,
|
|
126
|
+
` ${chalk.green(' --virtual-port=VIRTUAL_PORT')} Reported port ${chalk.yellow('[default: ' + argd['virtual-port'] + ']')}`,
|
|
127
|
+
` ${chalk.green(' --working-dir=PWD')} Use the given directory as working directory`,
|
|
128
|
+
].join('\n'),
|
|
129
|
+
[
|
|
130
|
+
` Preview rendered API docs based on local ${chalk.magenta('openapi.json')} path:`,
|
|
131
|
+
``,
|
|
132
|
+
` ${chalk.green(path.basename(process.argv[1]) + ' preview openapi.json')}`,
|
|
133
|
+
``,
|
|
134
|
+
` Preview rendered Swagger Petstore docs based on remote ${chalk.magenta('https://petstore.swagger.io/v2/swagger.json')} URL:`,
|
|
135
|
+
``,
|
|
136
|
+
` ${chalk.green(path.basename(process.argv[1]) + ' preview --title="Swagger Petstore" https://petstore.swagger.io/v2/swagger.json')}`,
|
|
137
|
+
'',
|
|
138
|
+
` Preview local API docs, enable CORS proxy and watch/reload on data changes:`,
|
|
139
|
+
``,
|
|
140
|
+
` ${chalk.green(path.basename(process.argv[1]) + ' preview -cw openapi.json')}`,
|
|
141
|
+
].join('\n'),
|
|
142
|
+
);
|
|
143
|
+
} else {
|
|
144
|
+
console.error(
|
|
145
|
+
`Elements CLI\n\n${chalk.yellow('Usage:')}\n%s\n\n${chalk.yellow('Options:')}\n%s\n\n${chalk.yellow('Commands:')}\n%s`,
|
|
146
|
+
` ${path.basename(process.argv[1])} command [options] [arguments]`,
|
|
147
|
+
[
|
|
148
|
+
` ${chalk.green('-h, --help')} Display this help message`,
|
|
149
|
+
` ${chalk.green('-v, --version')} Print version number`,
|
|
150
|
+
].join('\n'),
|
|
151
|
+
[
|
|
152
|
+
` ${chalk.green('export')} Export rendered API docs`,
|
|
153
|
+
` ${chalk.green('preview')} Preview rendered API docs`,
|
|
154
|
+
].join('\n'),
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
process.exit(argv.help ? 0 : 1);
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
// Watching remote files is not supported
|
|
162
162
|
|
|
163
163
|
if (/^http(s)?:\/\//i.test(argv._[1])) {
|
|
164
|
-
|
|
164
|
+
argv.watch = false;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
/**
|
|
168
168
|
* Replace double forward slashes, removes trailing slashes and optionally appends suffix
|
|
169
|
-
*
|
|
169
|
+
*
|
|
170
170
|
* @param {string} str The input string
|
|
171
171
|
* @param {string} suffix The optional suffix
|
|
172
|
-
*
|
|
172
|
+
*
|
|
173
173
|
* @returns {string}
|
|
174
174
|
*/
|
|
175
175
|
function sanitize(str, suffix = '') {
|
|
176
|
-
|
|
176
|
+
return str.replace(/\/+/g, '/').replace(/\/$/, '') + suffix;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
/**
|
|
180
180
|
* Upgrade HTTP server with web socket server capabilities
|
|
181
|
-
*
|
|
181
|
+
*
|
|
182
182
|
* @param {http.Server} server The HTTP server instance
|
|
183
|
-
*
|
|
183
|
+
*
|
|
184
184
|
* @returns {ws.WebSocketServer}
|
|
185
185
|
*/
|
|
186
186
|
function upgrade(server) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
187
|
+
const wss = new WebSocketServer({ server });
|
|
188
|
+
|
|
189
|
+
return wss.on('connection', (socket) => {
|
|
190
|
+
socket.on('message', (message) => {
|
|
191
|
+
const request = JSON.parse(message);
|
|
192
|
+
|
|
193
|
+
if (request.command === 'hello') {
|
|
194
|
+
const data = JSON.stringify({
|
|
195
|
+
command: 'hello',
|
|
196
|
+
protocols: [
|
|
197
|
+
'http://livereload.com/protocols/official-7',
|
|
198
|
+
'http://livereload.com/protocols/official-8',
|
|
199
|
+
'http://livereload.com/protocols/official-9',
|
|
200
|
+
'http://livereload.com/protocols/2.x-origin-version-negotiation',
|
|
201
|
+
'http://livereload.com/protocols/2.x-remote-control',
|
|
202
|
+
],
|
|
203
|
+
serverName: 'elements-server',
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
socket.send(data);
|
|
207
|
+
}
|
|
204
208
|
});
|
|
205
|
-
|
|
206
|
-
socket.send(data);
|
|
207
|
-
}
|
|
208
209
|
});
|
|
209
|
-
});
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
/**
|
|
213
213
|
* Create file system watcher and broatcast all file changes to every client
|
|
214
|
-
*
|
|
214
|
+
*
|
|
215
215
|
* @param {string} filePath The file path to watch
|
|
216
216
|
* @param {ws.WebSocketServer} server The web socket server instance
|
|
217
|
-
*
|
|
217
|
+
*
|
|
218
218
|
* @returns {chokidar.FSWatcher}
|
|
219
219
|
*/
|
|
220
220
|
function watch(filePath, server) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
return watcher.on('all', (filePath) => {
|
|
227
|
-
const data = JSON.stringify({
|
|
228
|
-
command: 'reload',
|
|
229
|
-
path: filePath,
|
|
221
|
+
const watcher = chokidar.watch(filePath, {
|
|
222
|
+
ignoreInitial: true,
|
|
223
|
+
usePolling: argv.poll,
|
|
230
224
|
});
|
|
231
225
|
|
|
232
|
-
|
|
233
|
-
|
|
226
|
+
return watcher.on('all', (filePath) => {
|
|
227
|
+
const data = JSON.stringify({
|
|
228
|
+
command: 'reload',
|
|
229
|
+
path: filePath,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
server.clients.forEach((socket) => socket.send(data));
|
|
233
|
+
});
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
// Define base href
|
|
@@ -240,49 +240,54 @@ const baseHref = sanitize(`/${argv['base-path']}`, '/');
|
|
|
240
240
|
// Define delimiters and variables
|
|
241
241
|
|
|
242
242
|
const delimiters = { open: '{{', close: '}}' },
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
243
|
+
variables = [argv.variable]
|
|
244
|
+
.flat()
|
|
245
|
+
.filter((variable) => !!variable)
|
|
246
|
+
.reduce((variables, variable) => {
|
|
247
|
+
const [name, value] = variable.split('=');
|
|
248
|
+
variables[name] = value;
|
|
249
|
+
return variables;
|
|
250
|
+
}, {});
|
|
248
251
|
|
|
249
252
|
// Export rendered API docs
|
|
250
253
|
|
|
251
254
|
if (argv._[0] === 'export') {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
255
|
+
const input = await readFile(path.resolve(__dirname, 'views', 'index.handlebars'));
|
|
256
|
+
const template = handlebars.compile(input.toString('utf8'));
|
|
257
|
+
const version = pkg.dependencies['@stoplight/elements'];
|
|
258
|
+
|
|
259
|
+
let tryItCorsProxy;
|
|
260
|
+
|
|
261
|
+
if (argv['cors-proxy'] && !argv['no-try-it']) {
|
|
262
|
+
tryItCorsProxy = argv['cors-proxy'];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
console.log(
|
|
266
|
+
template({
|
|
267
|
+
baseHref,
|
|
268
|
+
delimiters,
|
|
269
|
+
elements: {
|
|
270
|
+
apiDescriptionUrl: argv._[1],
|
|
271
|
+
basePath: baseHref,
|
|
272
|
+
hideInternal: argv['filter-internal'] ? 'true' : undefined,
|
|
273
|
+
hideTryIt: argv['no-try-it'] ? 'true' : undefined,
|
|
274
|
+
tryItCorsProxy,
|
|
275
|
+
tryItCredentialsPolicy: argv['credentials-policy'],
|
|
276
|
+
layout: argv.layout,
|
|
277
|
+
logo: argv.logo,
|
|
278
|
+
router: argv.router,
|
|
279
|
+
style: argv.style,
|
|
280
|
+
},
|
|
281
|
+
'elements-css': `https://unpkg.com/@stoplight/elements@${version}/styles.min.css`,
|
|
282
|
+
'elements-js': `https://unpkg.com/@stoplight/elements@${version}/web-components.min.js`,
|
|
283
|
+
layout: false,
|
|
284
|
+
livereload: false,
|
|
285
|
+
title: argv.title,
|
|
286
|
+
variables,
|
|
287
|
+
})
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
process.exit(0);
|
|
286
291
|
}
|
|
287
292
|
|
|
288
293
|
// Create express app
|
|
@@ -298,112 +303,112 @@ app.set('views', path.join(__dirname, 'views'));
|
|
|
298
303
|
// Serve assets from node_modules
|
|
299
304
|
|
|
300
305
|
const assets = {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
306
|
+
'livereload.js': require.resolve('livereload-js/dist/livereload.min.js'),
|
|
307
|
+
'styles.min.css': require.resolve('@stoplight/elements/styles.min.css'),
|
|
308
|
+
'web-components.min.js': require.resolve('@stoplight/elements/web-components.min.js'),
|
|
304
309
|
};
|
|
305
310
|
|
|
306
311
|
app.get(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
);
|
|
316
|
-
}
|
|
312
|
+
Object.keys(assets).map((asset) =>
|
|
313
|
+
sanitize(`/${argv['base-path']}/${asset}`)
|
|
314
|
+
),
|
|
315
|
+
(req, res) => {
|
|
316
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
317
|
+
|
|
318
|
+
send(req, assets[path.basename(url.pathname)]).pipe(res);
|
|
319
|
+
}
|
|
317
320
|
);
|
|
318
321
|
|
|
319
322
|
// Serve static files from working directory
|
|
320
323
|
|
|
321
|
-
app.use(
|
|
324
|
+
app.use(
|
|
325
|
+
sanitize(`/${argv['base-path']}`),
|
|
326
|
+
express.static(argv['working-dir'], { index: false })
|
|
327
|
+
);
|
|
322
328
|
|
|
323
329
|
// Handle CORS proxy requests
|
|
324
330
|
|
|
325
331
|
if (argv['with-cors-proxy'] && !argv['no-try-it']) {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
332
|
+
const proxy = corsAnywhere.createServer({
|
|
333
|
+
originWhitelist: [], // Allow all origins
|
|
334
|
+
requireHeaders: [], // Do not require any headers
|
|
335
|
+
removeHeaders: [], // Do not remove any headers
|
|
336
|
+
});
|
|
331
337
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
338
|
+
app.all(sanitize(`/${argv['base-path']}/_/*`), (req, res) => {
|
|
339
|
+
const pos = req.originalUrl.indexOf('?');
|
|
340
|
+
const queryString = pos === -1 ? '' : req.originalUrl.substring(pos);
|
|
335
341
|
|
|
336
|
-
|
|
342
|
+
req.url = `/${req.params['0']}${queryString}`;
|
|
337
343
|
|
|
338
|
-
|
|
339
|
-
|
|
344
|
+
proxy.emit('request', req, res);
|
|
345
|
+
});
|
|
340
346
|
}
|
|
341
347
|
|
|
342
348
|
// Render and serve index template
|
|
343
349
|
|
|
344
350
|
app.get(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
+
[sanitize(`/${argv['base-path']}`, '*'), sanitize(`/${argv['base-path']}`)],
|
|
352
|
+
(req, res) => {
|
|
353
|
+
let tryItCorsProxy;
|
|
354
|
+
|
|
355
|
+
if (argv['with-cors-proxy'] && !argv['no-try-it']) {
|
|
356
|
+
tryItCorsProxy = `http://${req.headers.host}${baseHref}_/`;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
res.render('index', {
|
|
360
|
+
baseHref,
|
|
361
|
+
delimiters,
|
|
362
|
+
elements: {
|
|
363
|
+
apiDescriptionUrl: argv._[1],
|
|
364
|
+
basePath: baseHref,
|
|
365
|
+
hideInternal: argv['filter-internal'] ? 'true' : undefined,
|
|
366
|
+
hideTryIt: argv['no-try-it'] ? 'true' : undefined,
|
|
367
|
+
tryItCorsProxy,
|
|
368
|
+
tryItCredentialsPolicy: argv['credentials-policy'],
|
|
369
|
+
layout: argv.layout,
|
|
370
|
+
logo: argv.logo,
|
|
371
|
+
router: argv.router,
|
|
372
|
+
style: argv.style,
|
|
373
|
+
},
|
|
374
|
+
'elements-css': 'styles.min.css',
|
|
375
|
+
'elements-js': 'web-components.min.js',
|
|
376
|
+
layout: false,
|
|
377
|
+
'livereload-js': argv.watch ? 'livereload.js' : undefined,
|
|
378
|
+
title: argv.title,
|
|
379
|
+
variables,
|
|
380
|
+
});
|
|
351
381
|
}
|
|
352
|
-
|
|
353
|
-
res.render('index', {
|
|
354
|
-
baseHref,
|
|
355
|
-
delimiters,
|
|
356
|
-
elements: {
|
|
357
|
-
apiDescriptionUrl: argv._[1],
|
|
358
|
-
basePath: baseHref,
|
|
359
|
-
hideInternal: argv['filter-internal'] ? 'true' : undefined,
|
|
360
|
-
hideTryIt: argv['no-try-it'] ? 'true' : undefined,
|
|
361
|
-
tryItCorsProxy,
|
|
362
|
-
tryItCredentialsPolicy: argv['credentials-policy'],
|
|
363
|
-
layout: argv.layout,
|
|
364
|
-
logo: argv.logo,
|
|
365
|
-
router: argv.router,
|
|
366
|
-
style: argv.style,
|
|
367
|
-
},
|
|
368
|
-
'elements-css': 'styles.min.css',
|
|
369
|
-
'elements-js': 'web-components.min.js',
|
|
370
|
-
layout: false,
|
|
371
|
-
'livereload-js': argv.watch ? 'livereload.js' : undefined,
|
|
372
|
-
title: argv.title,
|
|
373
|
-
variables,
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
382
|
);
|
|
377
383
|
|
|
378
384
|
// Listen for HTTP connections
|
|
379
385
|
|
|
380
386
|
const server = app.listen(argv.port, argv.hostname, () => {
|
|
381
|
-
|
|
382
|
-
`
|
|
383
|
-
);
|
|
384
|
-
console.error(
|
|
385
|
-
`Visit http://${argv['virtual-host']}:${argv['virtual-port']}${baseHref}`
|
|
386
|
-
);
|
|
387
|
+
console.error(`Elements server listening on ${argv.hostname}:${argv.port}`);
|
|
388
|
+
console.error(`Visit http://${argv['virtual-host']}:${argv['virtual-port']}${baseHref}`);
|
|
387
389
|
});
|
|
388
390
|
|
|
389
391
|
// Watch files in working directory and launch web socket server
|
|
390
392
|
|
|
391
393
|
const watcher = argv.watch
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
394
|
+
? watch(
|
|
395
|
+
argv['working-dir'],
|
|
396
|
+
upgrade(server).on('error', (err) => console.error(err))
|
|
397
|
+
)
|
|
398
|
+
.once('ready', () =>
|
|
399
|
+
console.error(`Watching ${path.resolve(argv['working-dir'])}`)
|
|
400
|
+
)
|
|
401
|
+
.on('error', (err) => console.error(err))
|
|
402
|
+
: undefined;
|
|
399
403
|
|
|
400
404
|
// Enable the graceful shutdown
|
|
401
405
|
|
|
402
406
|
gracefulShutdown(server, {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
407
|
+
onShutdown: () =>
|
|
408
|
+
new Promise((resolve) => {
|
|
409
|
+
if (watcher) {
|
|
410
|
+
watcher.close();
|
|
411
|
+
}
|
|
412
|
+
resolve();
|
|
413
|
+
}),
|
|
409
414
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skriptfabrik/elements-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "The missing CLI for beautiful, interactive API docs powered by with Stoplight Elements",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"stoplight",
|
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
},
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@stoplight/elements": "7.7.
|
|
24
|
+
"@stoplight/elements": "7.7.13",
|
|
25
25
|
"chalk": "^5.2.0",
|
|
26
26
|
"chokidar": "^3.5.3",
|
|
27
27
|
"cors-anywhere": "~0.4.4",
|
|
28
28
|
"express": "^4.18.2",
|
|
29
|
-
"express-handlebars": "^
|
|
29
|
+
"express-handlebars": "^7.0.4",
|
|
30
30
|
"handlebars": "^4.7.7",
|
|
31
31
|
"http-graceful-shutdown": "^3.1.12",
|
|
32
|
-
"livereload-js": "
|
|
32
|
+
"livereload-js": "^4.0.1",
|
|
33
33
|
"minimist": "^1.2.7",
|
|
34
34
|
"send": "~0.18.0",
|
|
35
|
-
"ws": "^8.
|
|
35
|
+
"ws": "^8.13.0"
|
|
36
36
|
},
|
|
37
37
|
"bin": {
|
|
38
38
|
"elements": "./elements-cli.mjs"
|