@skriptfabrik/elements-cli 0.5.0 → 0.5.2

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.
@@ -9,31 +9,25 @@ registries:
9
9
  replaces-base: true
10
10
 
11
11
  updates:
12
- - package-ecosystem: 'github-actions'
12
+ - package-ecosystem: 'docker'
13
13
  directory: '/'
14
14
  reviewers:
15
- - 'skriptfabrik/developers'
15
+ - 'skriptfabrik/docker-maintainers'
16
+ registries:
17
+ - 'dockerhub'
16
18
  schedule:
17
19
  interval: 'weekly'
18
- time: '08:00'
19
- timezone: 'Europe/Berlin'
20
20
 
21
- - package-ecosystem: 'npm'
21
+ - package-ecosystem: 'github-actions'
22
22
  directory: '/'
23
23
  reviewers:
24
- - 'skriptfabrik/developers'
24
+ - 'skriptfabrik/github-actions-maintainers'
25
25
  schedule:
26
26
  interval: 'weekly'
27
- time: '08:00'
28
- timezone: 'Europe/Berlin'
29
27
 
30
- - package-ecosystem: 'docker'
28
+ - package-ecosystem: 'npm'
31
29
  directory: '/'
32
30
  reviewers:
33
- - 'skriptfabrik/developers'
34
- registries:
35
- - 'dockerhub'
31
+ - 'skriptfabrik/npm-maintainers'
36
32
  schedule:
37
33
  interval: 'weekly'
38
- time: '08:00'
39
- timezone: 'Europe/Berlin'
@@ -1,12 +1,12 @@
1
1
  ## Describe your changes
2
2
 
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)
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
- - [ ] 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.
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.
@@ -19,12 +19,12 @@ jobs:
19
19
 
20
20
  steps:
21
21
  - name: Checkout
22
- uses: actions/checkout@v3
22
+ uses: actions/checkout@v4
23
23
  with:
24
24
  fetch-depth: 0
25
25
 
26
26
  - name: Install Node.js version ${{ env.NODE_VERSION }}
27
- uses: actions/setup-node@v3
27
+ uses: actions/setup-node@v4
28
28
  with:
29
29
  node-version: ${{ env.NODE_VERSION }}
30
30
 
@@ -48,27 +48,27 @@ jobs:
48
48
  npm version from-git --no-git-tag-version
49
49
 
50
50
  - name: Publish package
51
- uses: JS-DevTools/npm-publish@v1
51
+ uses: JS-DevTools/npm-publish@v3
52
52
  if: github.ref_type == 'tag'
53
53
  with:
54
54
  access: public
55
55
  token: ${{ secrets.NPM_TOKEN }}
56
56
 
57
57
  - name: Log in to DockerHub
58
- uses: docker/login-action@v2
58
+ uses: docker/login-action@v3
59
59
  with:
60
60
  username: ${{ secrets.DOCKERHUB_USERNAME }}
61
61
  password: ${{ secrets.DOCKERHUB_TOKEN }}
62
62
 
63
63
  - name: Set up QEMU
64
- uses: docker/setup-qemu-action@v2
64
+ uses: docker/setup-qemu-action@v3
65
65
 
66
66
  - name: Set up Docker Buildx
67
- uses: docker/setup-buildx-action@v2
67
+ uses: docker/setup-buildx-action@v3
68
68
 
69
69
  - name: Build and Push latest Docker image
70
70
  if: github.ref_name == 'main'
71
- uses: docker/build-push-action@v2
71
+ uses: docker/build-push-action@v6
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@v2
93
+ uses: docker/build-push-action@v6
94
94
  with:
95
95
  build-args: |-
96
96
  BUILDKIT_INLINE_CACHE=${{ env.DOCKER_BUILDKIT_INLINE_CACHE }}
package/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:18.14.0-alpine
1
+ FROM node:18.15.0-alpine
2
2
 
3
3
  LABEL maintainer="Daniel Schröder <daniel.schroeder@skriptfabrik.com>"
4
4
 
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
+ # Elements CLI
2
+
1
3
  [![NPM Version](https://img.shields.io/npm/v/@skriptfabrik/elements-cli)](https://www.npmjs.com/package/@skriptfabrik/elements-cli)
2
4
  [![NPM Downloads](https://img.shields.io/npm/dt/@skriptfabrik/elements-cli)](https://www.npmjs.com/package/@skriptfabrik/elements-cli)
3
5
  [![Continuous Integration](https://img.shields.io/github/actions/workflow/status/skriptfabrik/elements-cli/ci.yml)](https://github.com/skriptfabrik/elements-cli/actions/workflows/ci.yml)
4
6
 
5
- # Elements CLI
6
-
7
7
  > The missing CLI for beautiful, interactive API docs powered by with [Stoplight Elements](https://github.com/stoplightio/elements)
8
8
 
9
9
  ## Installation
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
- '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(),
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
- 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,
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
- console.log(pkg.version);
66
- process.exit(0);
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
- 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
- }
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
- process.exit(argv.help ? 0 : 1);
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
- argv.watch = false;
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
- return str.replace(/\/+/g, '/').replace(/\/$/, '') + suffix;
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
- 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',
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
- const watcher = chokidar.watch(filePath, {
222
- ignoreInitial: true,
223
- usePolling: argv.poll,
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
- server.clients.forEach((socket) => socket.send(data));
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
- variables = [argv.variable].flat().filter((variable) => !!variable).reduce((variables, variable) => {
244
- const [name, value] = variable.split('=');
245
- variables[name] = value;
246
- return variables;
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
- const input = (await readFile(path.resolve(__dirname, 'views', 'index.handlebars'))).toString('utf8');
253
- const template = handlebars.compile(input);
254
- const version = pkg.dependencies['@stoplight/elements'];
255
-
256
- let tryItCorsProxy;
257
-
258
- if (argv['cors-proxy'] && !argv['no-try-it']) {
259
- tryItCorsProxy = argv['cors-proxy'];
260
- }
261
-
262
- console.log(template({
263
- baseHref,
264
- delimiters,
265
- elements: {
266
- apiDescriptionUrl: argv._[1],
267
- basePath: baseHref,
268
- hideInternal: argv['filter-internal'] ? 'true' : undefined,
269
- hideTryIt: argv['no-try-it'] ? 'true' : undefined,
270
- tryItCorsProxy,
271
- tryItCredentialsPolicy: argv['credentials-policy'],
272
- layout: argv.layout,
273
- logo: argv.logo,
274
- router: argv.router,
275
- style: argv.style,
276
- },
277
- 'elements-css': `https://unpkg.com/@stoplight/elements@${version}/styles.min.css`,
278
- 'elements-js': `https://unpkg.com/@stoplight/elements@${version}/web-components.min.js`,
279
- layout: false,
280
- livereload: false,
281
- title: argv.title,
282
- variables,
283
- }));
284
-
285
- process.exit(0);
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
- 'livereload.js': require.resolve('livereload-js/dist/livereload.min.js'),
302
- 'styles.min.css': require.resolve('@stoplight/elements/styles.min.css'),
303
- 'web-components.min.js': require.resolve('@stoplight/elements/web-components.min.js'),
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
- Object.keys(assets).map((asset) =>
308
- sanitize(`/${argv['base-path']}/${asset}`)
309
- ),
310
- (req, res) => {
311
- const url = new URL(req.url, `http://${req.headers.host}`);
312
-
313
- send(req, assets[path.basename(url.pathname)]).pipe(
314
- res
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(sanitize(`/${argv['base-path']}`), express.static(argv['working-dir'], { index: false }));
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
- const proxy = corsAnywhere.createServer({
327
- originWhitelist: [], // Allow all origins
328
- requireHeaders: [], // Do not require any headers
329
- removeHeaders: [] // Do not remove any headers
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
- app.all(sanitize(`/${argv['base-path']}/_/*`), (req, res) => {
333
- const pos = req.originalUrl.indexOf('?');
334
- const queryString = pos === -1 ? '' : req.originalUrl.substring(pos);
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
- req.url = `/${req.params['0']}${queryString}`;
342
+ req.url = `/${req.params['0']}${queryString}`;
337
343
 
338
- proxy.emit('request', req, res);
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
- [sanitize(`/${argv['base-path']}`, '*'), sanitize(`/${argv['base-path']}`)],
346
- (req, res) => {
347
- let tryItCorsProxy;
348
-
349
- if (argv['with-cors-proxy'] && !argv['no-try-it']) {
350
- tryItCorsProxy = `http://${req.headers.host}${baseHref}_/`;
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
- console.error(
382
- `Elements server listening on ${argv.hostname}:${argv.port}`
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
- ? watch(
393
- argv['working-dir'],
394
- upgrade(server).on('error', (err) => console.error(err))
395
- )
396
- .once('ready', () => console.error(`Watching ${path.resolve(argv['working-dir'])}`))
397
- .on('error', (err) => console.error(err))
398
- : undefined;
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
- onShutdown: () => new Promise((resolve) => {
404
- if (watcher) {
405
- watcher.close();
406
- }
407
- resolve();
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.0",
3
+ "version": "0.5.2",
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.10",
24
+ "@stoplight/elements": "8.4.7",
25
25
  "chalk": "^5.2.0",
26
- "chokidar": "^3.5.3",
26
+ "chokidar": "^4.0.0",
27
27
  "cors-anywhere": "~0.4.4",
28
- "express": "^4.18.2",
29
- "express-handlebars": "^6.0.7",
28
+ "express": "^4.19.2",
29
+ "express-handlebars": "^8.0.1",
30
30
  "handlebars": "^4.7.7",
31
31
  "http-graceful-shutdown": "^3.1.12",
32
- "livereload-js": "3.4.1",
32
+ "livereload-js": "^4.0.1",
33
33
  "minimist": "^1.2.7",
34
- "send": "~0.18.0",
35
- "ws": "^8.12.0"
34
+ "send": "~1.1.0",
35
+ "ws": "^8.13.0"
36
36
  },
37
37
  "bin": {
38
38
  "elements": "./elements-cli.mjs"