@heroku-cli/plugin-devcenter 0.0.2 → 2.0.0
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/LICENSE.txt +22 -0
- package/README.md +132 -17
- package/dist/commands/devcenter/open.d.ts +9 -0
- package/dist/commands/devcenter/open.d.ts.map +1 -0
- package/dist/commands/devcenter/open.js +33 -0
- package/dist/commands/devcenter/open.js.map +1 -0
- package/dist/commands/devcenter/preview.d.ts +14 -0
- package/dist/commands/devcenter/preview.d.ts.map +1 -0
- package/dist/commands/devcenter/preview.js +40 -0
- package/dist/commands/devcenter/preview.js.map +1 -0
- package/dist/commands/devcenter/pull.d.ts +12 -0
- package/dist/commands/devcenter/pull.d.ts.map +1 -0
- package/dist/commands/devcenter/pull.js +52 -0
- package/dist/commands/devcenter/pull.js.map +1 -0
- package/dist/commands/devcenter/push.d.ts +9 -0
- package/dist/commands/devcenter/push.d.ts.map +1 -0
- package/dist/commands/devcenter/push.js +105 -0
- package/dist/commands/devcenter/push.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/article-file.d.ts +21 -0
- package/dist/lib/article-file.d.ts.map +1 -0
- package/dist/lib/article-file.js +48 -0
- package/dist/lib/article-file.js.map +1 -0
- package/dist/lib/article-not-found.d.ts +3 -0
- package/dist/lib/article-not-found.d.ts.map +1 -0
- package/dist/lib/article-not-found.js +16 -0
- package/dist/lib/article-not-found.js.map +1 -0
- package/dist/lib/article-resolve.d.ts +23 -0
- package/dist/lib/article-resolve.d.ts.map +1 -0
- package/dist/lib/article-resolve.js +61 -0
- package/dist/lib/article-resolve.js.map +1 -0
- package/dist/lib/article-split.d.ts +9 -0
- package/dist/lib/article-split.d.ts.map +1 -0
- package/dist/lib/article-split.js +15 -0
- package/dist/lib/article-split.js.map +1 -0
- package/dist/lib/devcenter-client.d.ts +39 -0
- package/dist/lib/devcenter-client.d.ts.map +1 -0
- package/dist/lib/devcenter-client.js +119 -0
- package/dist/lib/devcenter-client.js.map +1 -0
- package/dist/lib/heroku-api-auth.d.ts +7 -0
- package/dist/lib/heroku-api-auth.d.ts.map +1 -0
- package/dist/lib/heroku-api-auth.js +12 -0
- package/dist/lib/heroku-api-auth.js.map +1 -0
- package/dist/lib/paths.d.ts +18 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +48 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/preview-server.d.ts +17 -0
- package/dist/lib/preview-server.d.ts.map +1 -0
- package/dist/lib/preview-server.js +94 -0
- package/dist/lib/preview-server.js.map +1 -0
- package/dist/lib/preview-templates.d.ts +7 -0
- package/dist/lib/preview-templates.d.ts.map +1 -0
- package/dist/lib/preview-templates.js +93 -0
- package/dist/lib/preview-templates.js.map +1 -0
- package/oclif.manifest.json +172 -1
- package/package.json +86 -49
- package/lib/commands/docs.d.ts +0 -25
- package/lib/commands/docs.js +0 -29
- package/lib/index.d.ts +0 -2
- package/lib/index.js +0 -3
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Heroku
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,31 +1,146 @@
|
|
|
1
|
-
|
|
2
|
-
====
|
|
1
|
+
# @heroku-cli/plugin-devcenter
|
|
3
2
|
|
|
4
|
-
CLI plugin to
|
|
3
|
+
Heroku CLI plugin to interact with Heroku Dev Center
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
[](https://npmjs.org/package/@heroku-cli/plugin-devcenter)
|
|
6
|
+
[](https://github.com/heroku/devcenter-cli/blob/main/LICENSE.txt)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
heroku plugins:install @heroku-cli/plugin-devcenter
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
<!-- usage -->
|
|
15
|
+
```sh-session
|
|
16
|
+
$ npm install -g @heroku-cli/plugin-devcenter
|
|
17
|
+
$ heroku COMMAND
|
|
18
|
+
running command...
|
|
19
|
+
$ heroku (--version)
|
|
20
|
+
@heroku-cli/plugin-devcenter/2.0.0 darwin-arm64 node-v24.14.0
|
|
21
|
+
$ heroku --help [COMMAND]
|
|
22
|
+
USAGE
|
|
23
|
+
$ heroku COMMAND
|
|
24
|
+
...
|
|
25
|
+
```
|
|
26
|
+
<!-- usagestop -->
|
|
27
|
+
|
|
28
|
+
## Commands
|
|
9
29
|
|
|
10
|
-
# Commands
|
|
11
30
|
<!-- commands -->
|
|
12
|
-
* [`
|
|
31
|
+
* [`heroku devcenter:open SLUG`](#heroku-devcenteropen-slug)
|
|
32
|
+
* [`heroku devcenter:preview SLUG`](#heroku-devcenterpreview-slug)
|
|
33
|
+
* [`heroku devcenter:pull SLUGORURL`](#heroku-devcenterpull-slugorurl)
|
|
34
|
+
* [`heroku devcenter:push SLUG`](#heroku-devcenterpush-slug)
|
|
35
|
+
|
|
36
|
+
## `heroku devcenter:open SLUG`
|
|
37
|
+
|
|
38
|
+
open a Dev Center article in the browser (uses Heroku credentials for private or draft content when available)
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
USAGE
|
|
42
|
+
$ heroku devcenter:open SLUG [--prompt]
|
|
43
|
+
|
|
44
|
+
ARGUMENTS
|
|
45
|
+
SLUG article slug (e.g. ps for https://devcenter.heroku.com/articles/ps)
|
|
13
46
|
|
|
14
|
-
|
|
47
|
+
GLOBAL FLAGS
|
|
48
|
+
--prompt interactively prompt for command arguments and flags
|
|
15
49
|
|
|
16
|
-
|
|
50
|
+
DESCRIPTION
|
|
51
|
+
open a Dev Center article in the browser (uses Heroku credentials for private or draft content when available)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
_See code: [src/commands/devcenter/open.ts](https://github.com/heroku/devcenter-cli/blob/v2.0.0/src/commands/devcenter/open.ts)_
|
|
55
|
+
|
|
56
|
+
## `heroku devcenter:preview SLUG`
|
|
57
|
+
|
|
58
|
+
preview a local Dev Center article in the browser with live reload
|
|
17
59
|
|
|
18
60
|
```
|
|
19
61
|
USAGE
|
|
20
|
-
$
|
|
62
|
+
$ heroku devcenter:preview SLUG [--prompt] [--host <value>] [--port <value>]
|
|
21
63
|
|
|
22
|
-
|
|
23
|
-
|
|
64
|
+
ARGUMENTS
|
|
65
|
+
SLUG article slug (local <slug>.md file)
|
|
24
66
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
67
|
+
FLAGS
|
|
68
|
+
--host=<value> [default: 127.0.0.1] bind host for the preview server
|
|
69
|
+
--port=<value> [default: 3000] port for the preview server
|
|
70
|
+
|
|
71
|
+
GLOBAL FLAGS
|
|
72
|
+
--prompt interactively prompt for command arguments and flags
|
|
73
|
+
|
|
74
|
+
DESCRIPTION
|
|
75
|
+
preview a local Dev Center article in the browser with live reload
|
|
28
76
|
```
|
|
29
77
|
|
|
30
|
-
_See code: [src/commands/
|
|
78
|
+
_See code: [src/commands/devcenter/preview.ts](https://github.com/heroku/devcenter-cli/blob/v2.0.0/src/commands/devcenter/preview.ts)_
|
|
79
|
+
|
|
80
|
+
## `heroku devcenter:pull SLUGORURL`
|
|
81
|
+
|
|
82
|
+
save a local copy of a Dev Center article
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
USAGE
|
|
86
|
+
$ heroku devcenter:pull SLUGORURL [--prompt] [-f]
|
|
87
|
+
|
|
88
|
+
ARGUMENTS
|
|
89
|
+
SLUGORURL article slug or full Dev Center article URL
|
|
90
|
+
|
|
91
|
+
FLAGS
|
|
92
|
+
-f, --force overwrite an existing local file without prompting
|
|
93
|
+
|
|
94
|
+
GLOBAL FLAGS
|
|
95
|
+
--prompt interactively prompt for command arguments and flags
|
|
96
|
+
|
|
97
|
+
DESCRIPTION
|
|
98
|
+
save a local copy of a Dev Center article
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
_See code: [src/commands/devcenter/pull.ts](https://github.com/heroku/devcenter-cli/blob/v2.0.0/src/commands/devcenter/pull.ts)_
|
|
102
|
+
|
|
103
|
+
## `heroku devcenter:push SLUG`
|
|
104
|
+
|
|
105
|
+
update a Dev Center article from a local markdown file
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
USAGE
|
|
109
|
+
$ heroku devcenter:push SLUG [--prompt]
|
|
110
|
+
|
|
111
|
+
ARGUMENTS
|
|
112
|
+
SLUG article slug (optional .md suffix is ignored)
|
|
113
|
+
|
|
114
|
+
GLOBAL FLAGS
|
|
115
|
+
--prompt interactively prompt for command arguments and flags
|
|
116
|
+
|
|
117
|
+
DESCRIPTION
|
|
118
|
+
update a Dev Center article from a local markdown file
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
_See code: [src/commands/devcenter/push.ts](https://github.com/heroku/devcenter-cli/blob/v2.0.0/src/commands/devcenter/push.ts)_
|
|
31
122
|
<!-- commandsstop -->
|
|
123
|
+
|
|
124
|
+
## Development
|
|
125
|
+
|
|
126
|
+
TypeScript code lives under `src/` with tests under `test/`. With Node 22+, run `npm install` and `npm test`.
|
|
127
|
+
|
|
128
|
+
If you have a Dev Center instance, you can point your CLI to it by setting the `DEVCENTER_BASE_URL` environment variable:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
export DEVCENTER_BASE_URL=http://localhost:3000
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Verbose logging uses the [`debug`](https://www.npmjs.com/package/debug) package:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
DEBUG=devcenter:open heroku devcenter:open my-article
|
|
138
|
+
DEBUG=devcenter:preview heroku devcenter:preview my-article
|
|
139
|
+
DEBUG=devcenter:* heroku devcenter:open my-article
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
See [LICENSE.txt](LICENSE.txt) file.
|
|
145
|
+
|
|
146
|
+
The `preview` command uses the [Font Awesome](http://fontawesome.io/) vector icons, which have their own [License](https://github.com/FortAwesome/Font-Awesome#license).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
export default class Open extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
slug: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=open.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../../src/commands/devcenter/open.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAA;AAY3C,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAC,IAAI;;MAKV;IACD,MAAM,CAAC,WAAW,SACkG;IAE9G,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAiB3B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
import { Args } from '@oclif/core';
|
|
3
|
+
import createDebug from 'debug';
|
|
4
|
+
import open from 'open';
|
|
5
|
+
import { formatArticleNotFoundMessage } from '../../lib/article-not-found.js';
|
|
6
|
+
import { fetchArticleJsonForSlug } from '../../lib/article-resolve.js';
|
|
7
|
+
import { DevcenterClient } from '../../lib/devcenter-client.js';
|
|
8
|
+
import { articlePath, getDevcenterBaseUrl } from '../../lib/paths.js';
|
|
9
|
+
const dbg = createDebug('devcenter:open');
|
|
10
|
+
export default class Open extends Command {
|
|
11
|
+
static args = {
|
|
12
|
+
slug: Args.string({
|
|
13
|
+
description: 'article slug (e.g. ps for https://devcenter.heroku.com/articles/ps)',
|
|
14
|
+
required: true,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
static description = 'open a Dev Center article in the browser (uses Heroku credentials for private or draft content when available)';
|
|
18
|
+
async run() {
|
|
19
|
+
const { args } = await this.parse(Open);
|
|
20
|
+
const slug = args.slug.trim();
|
|
21
|
+
const client = new DevcenterClient();
|
|
22
|
+
dbg(`baseUrl=${getDevcenterBaseUrl()} path=${articlePath(slug)} expectedSlug=${slug}`);
|
|
23
|
+
const token = await this.heroku.getAuth();
|
|
24
|
+
const article = await fetchArticleJsonForSlug(client, slug, token, dbg);
|
|
25
|
+
if (!article) {
|
|
26
|
+
const msg = await formatArticleNotFoundMessage(client, slug);
|
|
27
|
+
this.error(msg, { exit: 1 });
|
|
28
|
+
}
|
|
29
|
+
dbg('Article found, opening');
|
|
30
|
+
await open(`${getDevcenterBaseUrl()}${articlePath(slug)}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=open.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../../src/commands/devcenter/open.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAC,IAAI,EAAC,MAAM,aAAa,CAAA;AAChC,OAAO,WAAW,MAAM,OAAO,CAAA;AAC/B,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,OAAO,EAAC,4BAA4B,EAAC,MAAM,gCAAgC,CAAA;AAC3E,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAC,eAAe,EAAC,MAAM,+BAA+B,CAAA;AAC7D,OAAO,EAAC,WAAW,EAAE,mBAAmB,EAAC,MAAM,oBAAoB,CAAA;AAEnE,MAAM,GAAG,GAAG,WAAW,CAAC,gBAAgB,CAAC,CAAA;AAEzC,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAC,IAAI,GAAG;QACZ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;YAChB,WAAW,EAAE,qEAAqE;YAClF,QAAQ,EAAE,IAAI;SACf,CAAC;KACH,CAAA;IACD,MAAM,CAAC,WAAW,GACd,gHAAgH,CAAA;IAEpH,KAAK,CAAC,GAAG;QACP,MAAM,EAAC,IAAI,EAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;QAC7B,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;QAEpC,GAAG,CAAC,WAAW,mBAAmB,EAAE,SAAS,WAAW,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAA;QAEtF,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;QACzC,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;QACvE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,MAAM,4BAA4B,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;YAC5D,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAC,IAAI,EAAE,CAAC,EAAC,CAAC,CAAA;QAC5B,CAAC;QAED,GAAG,CAAC,wBAAwB,CAAC,CAAA;QAC7B,MAAM,IAAI,CAAC,GAAG,mBAAmB,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC5D,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
export default class Preview extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
slug: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static flags: {
|
|
8
|
+
host: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
port: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
};
|
|
11
|
+
static id: string;
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=preview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../../src/commands/devcenter/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAA;AAO3C,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,OAAO;IAC1C,MAAM,CAAC,IAAI;;MAKV;IACD,MAAM,CAAC,WAAW,SAAuE;IACzF,MAAM,CAAC,KAAK;;;MASX;IACD,MAAM,CAAC,EAAE,SAAsB;IAEzB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAe3B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { mdFilePath } from '../../lib/paths.js';
|
|
5
|
+
import { runPreview } from '../../lib/preview-server.js';
|
|
6
|
+
export default class Preview extends Command {
|
|
7
|
+
static args = {
|
|
8
|
+
slug: Args.string({
|
|
9
|
+
description: 'article slug (local <slug>.md file)',
|
|
10
|
+
required: true,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static description = 'preview a local Dev Center article in the browser with live reload';
|
|
14
|
+
static flags = {
|
|
15
|
+
host: Flags.string({
|
|
16
|
+
default: '127.0.0.1',
|
|
17
|
+
description: 'bind host for the preview server',
|
|
18
|
+
}),
|
|
19
|
+
port: Flags.integer({
|
|
20
|
+
default: 3000,
|
|
21
|
+
description: 'port for the preview server',
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
static id = 'devcenter:preview';
|
|
25
|
+
async run() {
|
|
26
|
+
const { args, flags } = await this.parse(Preview);
|
|
27
|
+
const slug = args.slug.replace(/\.md$/i, '').trim();
|
|
28
|
+
const mdPath = mdFilePath(slug);
|
|
29
|
+
if (!existsSync(mdPath)) {
|
|
30
|
+
this.error(`Can't find ${mdPath} file - you may want to \`heroku devcenter:pull ${slug}\``, { exit: 1 });
|
|
31
|
+
}
|
|
32
|
+
await runPreview({
|
|
33
|
+
host: flags.host,
|
|
34
|
+
mdPath,
|
|
35
|
+
port: flags.port,
|
|
36
|
+
slug,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","sourceRoot":"","sources":["../../../src/commands/devcenter/preview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAC,IAAI,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,EAAC,UAAU,EAAC,MAAM,SAAS,CAAA;AAElC,OAAO,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAC,UAAU,EAAC,MAAM,6BAA6B,CAAA;AAEtD,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,OAAO;IAC1C,MAAM,CAAC,IAAI,GAAG;QACZ,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;YAChB,WAAW,EAAE,qCAAqC;YAClD,QAAQ,EAAE,IAAI;SACf,CAAC;KACH,CAAA;IACD,MAAM,CAAC,WAAW,GAAG,oEAAoE,CAAA;IACzF,MAAM,CAAC,KAAK,GAAG;QACb,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;YACjB,OAAO,EAAE,WAAW;YACpB,WAAW,EAAE,kCAAkC;SAChD,CAAC;QACF,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,6BAA6B;SAC3C,CAAC;KACH,CAAA;IACD,MAAM,CAAC,EAAE,GAAG,mBAAmB,CAAA;IAE/B,KAAK,CAAC,GAAG;QACP,MAAM,EAAC,IAAI,EAAE,KAAK,EAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;QACnD,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAA;QAC/B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,cAAc,MAAM,mDAAmD,IAAI,IAAI,EAAE,EAAC,IAAI,EAAE,CAAC,EAAC,CAAC,CAAA;QACxG,CAAC;QAED,MAAM,UAAU,CAAC;YACf,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,MAAM;YACN,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI;SACL,CAAC,CAAA;IACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
export default class Pull extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
slugOrUrl: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static flags: {
|
|
8
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=pull.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/commands/devcenter/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAA;AAmB3C,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAC,IAAI;;MAKV;IACD,MAAM,CAAC,WAAW,SAA8C;IAChE,MAAM,CAAC,KAAK;;MAKX;IAEK,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA6B3B"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
import { confirm } from '@heroku/heroku-cli-util/hux';
|
|
3
|
+
import { Args, Flags } from '@oclif/core';
|
|
4
|
+
import createDebug from 'debug';
|
|
5
|
+
import { existsSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { stringify as stringifyYaml } from 'yaml';
|
|
7
|
+
import { formatArticleNotFoundMessage } from '../../lib/article-not-found.js';
|
|
8
|
+
import { fetchArticleJsonForSlug } from '../../lib/article-resolve.js';
|
|
9
|
+
import { DevcenterClient } from '../../lib/devcenter-client.js';
|
|
10
|
+
import { articleApiPath, getDevcenterBaseUrl, mdFilePath, slugFromArticleUrl, } from '../../lib/paths.js';
|
|
11
|
+
const dbg = createDebug('devcenter:pull');
|
|
12
|
+
export default class Pull extends Command {
|
|
13
|
+
static args = {
|
|
14
|
+
slugOrUrl: Args.string({
|
|
15
|
+
description: 'article slug or full Dev Center article URL',
|
|
16
|
+
required: true,
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
static description = 'save a local copy of a Dev Center article';
|
|
20
|
+
static flags = {
|
|
21
|
+
force: Flags.boolean({
|
|
22
|
+
char: 'f',
|
|
23
|
+
description: 'overwrite an existing local file without prompting',
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
const { args, flags } = await this.parse(Pull);
|
|
28
|
+
const raw = args.slugOrUrl.trim();
|
|
29
|
+
const slug = slugFromArticleUrl(raw).trim();
|
|
30
|
+
const client = new DevcenterClient();
|
|
31
|
+
dbg(`baseUrl=${getDevcenterBaseUrl()} path=${articleApiPath(slug)} expectedSlug=${slug}`);
|
|
32
|
+
const token = await this.heroku.getAuth();
|
|
33
|
+
const article = await fetchArticleJsonForSlug(client, slug, token, dbg);
|
|
34
|
+
if (!article) {
|
|
35
|
+
const msg = await formatArticleNotFoundMessage(client, slug);
|
|
36
|
+
this.error(msg, { exit: 1 });
|
|
37
|
+
}
|
|
38
|
+
const metadata = { id: article.id, title: article.title };
|
|
39
|
+
const filePath = mdFilePath(slug);
|
|
40
|
+
if (!flags.force && existsSync(filePath)) {
|
|
41
|
+
const shouldOverwrite = await confirm(`The file ${filePath} already exists - overwrite?`);
|
|
42
|
+
if (!shouldOverwrite) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const yamlBlock = stringifyYaml(metadata).trimEnd();
|
|
47
|
+
const fileContent = `${yamlBlock}\n\n${article.content}`;
|
|
48
|
+
writeFileSync(filePath, fileContent, 'utf8');
|
|
49
|
+
this.log(`"${metadata.title}" article saved as ${filePath}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../../src/commands/devcenter/pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
export default class Push extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
slug: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../src/commands/devcenter/push.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,qBAAqB,CAAA;AAmC3C,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAC,IAAI;;MAKV;IACD,MAAM,CAAC,WAAW,SAA2D;IAEvE,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA4D3B"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Command } from '@heroku-cli/command';
|
|
2
|
+
import { Args } from '@oclif/core';
|
|
3
|
+
import createDebug from 'debug';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { stringify as stringifyYaml } from 'yaml';
|
|
6
|
+
import { ArticleFile } from '../../lib/article-file.js';
|
|
7
|
+
import { DevcenterClient } from '../../lib/devcenter-client.js';
|
|
8
|
+
import { mdFilePath } from '../../lib/paths.js';
|
|
9
|
+
const dbg = createDebug('devcenter:push');
|
|
10
|
+
function hasValidationErrors(body) {
|
|
11
|
+
if (body === undefined || body === null) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
if (Array.isArray(body)) {
|
|
15
|
+
return body.length > 0;
|
|
16
|
+
}
|
|
17
|
+
if (typeof body === 'object') {
|
|
18
|
+
return Object.keys(body).length > 0;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
export default class Push extends Command {
|
|
23
|
+
static args = {
|
|
24
|
+
slug: Args.string({
|
|
25
|
+
description: 'article slug (optional .md suffix is ignored)',
|
|
26
|
+
required: true,
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
static description = 'update a Dev Center article from a local markdown file';
|
|
30
|
+
async run() {
|
|
31
|
+
const { args } = await this.parse(Push);
|
|
32
|
+
const slug = args.slug.replace(/\.md$/i, '').trim();
|
|
33
|
+
const mdPath = mdFilePath(slug);
|
|
34
|
+
if (!existsSync(mdPath)) {
|
|
35
|
+
this.error(`Can't find ${mdPath} file - you may want to \`heroku devcenter:pull ${slug}\``, { exit: 1 });
|
|
36
|
+
}
|
|
37
|
+
const article = ArticleFile.read(mdPath);
|
|
38
|
+
if (article.parsingError) {
|
|
39
|
+
this.error(`The content of ${mdPath} can't be parsed properly, fix it and try again.`, { exit: 1 });
|
|
40
|
+
}
|
|
41
|
+
const token = await this.heroku.getAuth();
|
|
42
|
+
if (!token) {
|
|
43
|
+
this.error('Heroku credentials not found. Run `heroku login`.', { exit: 1 });
|
|
44
|
+
}
|
|
45
|
+
const client = new DevcenterClient();
|
|
46
|
+
const formParams = {
|
|
47
|
+
'article[content]': article.content,
|
|
48
|
+
'article[title]': String(article.metadata.title),
|
|
49
|
+
};
|
|
50
|
+
dbg(`Pushing article id=${article.metadata.id} title="${article.metadata.title}"`);
|
|
51
|
+
const broken = await client.checkBrokenLinks(token, article.content);
|
|
52
|
+
dbg(`Broken link check: ${Array.isArray(broken.body) ? broken.body.length : 0} issues`);
|
|
53
|
+
const links = broken.body;
|
|
54
|
+
if (Array.isArray(links) && links.length > 0) {
|
|
55
|
+
this.log(`The article "${slug}" contains broken link/s:`);
|
|
56
|
+
for (const link of links) {
|
|
57
|
+
this.log(`- [${link.text}](${link.url})`);
|
|
58
|
+
}
|
|
59
|
+
this.log('');
|
|
60
|
+
}
|
|
61
|
+
const validated = await client.validateArticle(token, article.metadata.id, formParams);
|
|
62
|
+
dbg(`Validation response: status=${validated.status} ok=${validated.ok}`);
|
|
63
|
+
if (hasValidationErrors(validated.body)) {
|
|
64
|
+
const dumped = stringifyYaml(validated.body);
|
|
65
|
+
this.error(`The article "${slug}" can't be saved:\n${dumped}`, { exit: 1 });
|
|
66
|
+
}
|
|
67
|
+
const updated = await client.updateArticle(token, article.metadata.id, formParams);
|
|
68
|
+
dbg(`Update response: status=${updated.status} ok=${updated.ok}`);
|
|
69
|
+
if (!updated.ok) {
|
|
70
|
+
const errBody = updated.body;
|
|
71
|
+
this.error(`Error pushing "${slug}": ${errBody.error ?? updated.status}`, { exit: 1 });
|
|
72
|
+
}
|
|
73
|
+
const result = updated.body;
|
|
74
|
+
const verb = statusVerb(result.status);
|
|
75
|
+
if (verb && result.title && result.url) {
|
|
76
|
+
this.log(`Article "${result.title}" ${verb} to ${result.url}`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.log('Article update completed.');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function statusVerb(status) {
|
|
84
|
+
switch (status) {
|
|
85
|
+
case 'archived': {
|
|
86
|
+
return 'archived';
|
|
87
|
+
}
|
|
88
|
+
case 'draft': {
|
|
89
|
+
return 'pushed in draft mode';
|
|
90
|
+
}
|
|
91
|
+
case 'published': {
|
|
92
|
+
return 'published';
|
|
93
|
+
}
|
|
94
|
+
case 'published_quietly': {
|
|
95
|
+
return 'published quietly';
|
|
96
|
+
}
|
|
97
|
+
case 'staging': {
|
|
98
|
+
return 'pushed as staging mode';
|
|
99
|
+
}
|
|
100
|
+
default: {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../../src/commands/devcenter/push.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type ArticleMetadata = {
|
|
2
|
+
id: number | string;
|
|
3
|
+
title: string;
|
|
4
|
+
};
|
|
5
|
+
export type TocEntry = {
|
|
6
|
+
id: string;
|
|
7
|
+
text: string;
|
|
8
|
+
};
|
|
9
|
+
export declare class ArticleFile {
|
|
10
|
+
content: string;
|
|
11
|
+
html: string;
|
|
12
|
+
metadata: ArticleMetadata;
|
|
13
|
+
parsingError?: string;
|
|
14
|
+
toc: TocEntry[];
|
|
15
|
+
constructor(opts: {
|
|
16
|
+
content?: string;
|
|
17
|
+
metadata?: Partial<ArticleMetadata>;
|
|
18
|
+
});
|
|
19
|
+
static read(srcPath: string): ArticleFile;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=article-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"article-file.d.ts","sourceRoot":"","sources":["../../src/lib/article-file.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAKD,MAAM,MAAM,QAAQ,GAAG;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAA;AAEjD,qBAAa,WAAW;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,eAAe,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,GAAG,EAAE,QAAQ,EAAE,CAAA;gBAEH,IAAI,EAAE;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;KAAC;IA0B1E,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW;CAM1C"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as cheerio from 'cheerio';
|
|
2
|
+
import MarkdownIt from 'markdown-it';
|
|
3
|
+
import anchor from 'markdown-it-anchor';
|
|
4
|
+
import { readFileSync } from 'node:fs';
|
|
5
|
+
import { parse as parseYaml } from 'yaml';
|
|
6
|
+
import { splitMetadataBody } from './article-split.js';
|
|
7
|
+
const md = new MarkdownIt({ html: false, linkify: true, typographer: true });
|
|
8
|
+
md.use(anchor, { permalink: false });
|
|
9
|
+
export class ArticleFile {
|
|
10
|
+
content;
|
|
11
|
+
html;
|
|
12
|
+
metadata;
|
|
13
|
+
parsingError;
|
|
14
|
+
toc;
|
|
15
|
+
constructor(opts) {
|
|
16
|
+
this.metadata = opts.metadata;
|
|
17
|
+
this.content = opts.content ?? '';
|
|
18
|
+
try {
|
|
19
|
+
this.html = md.render(this.content);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
this.parsingError = error instanceof Error ? error.message : String(error);
|
|
23
|
+
this.html = '';
|
|
24
|
+
}
|
|
25
|
+
if (this.html) {
|
|
26
|
+
const $ = cheerio.load(this.html);
|
|
27
|
+
this.toc = $('h2')
|
|
28
|
+
.toArray()
|
|
29
|
+
.map(el => {
|
|
30
|
+
const $el = $(el);
|
|
31
|
+
return {
|
|
32
|
+
id: $el.attr('id') ?? '',
|
|
33
|
+
text: $el.text(),
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.toc = [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
static read(srcPath) {
|
|
42
|
+
const src = readFileSync(srcPath, 'utf8');
|
|
43
|
+
const { body, yamlText } = splitMetadataBody(src);
|
|
44
|
+
const metadata = parseYaml(yamlText);
|
|
45
|
+
return new ArticleFile({ content: body, metadata });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=article-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"article-file.js","sourceRoot":"","sources":["../../src/lib/article-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAClC,OAAO,UAAU,MAAM,aAAa,CAAA;AACpC,OAAO,MAAM,MAAM,oBAAoB,CAAA;AACvC,OAAO,EAAC,YAAY,EAAC,MAAM,SAAS,CAAA;AACpC,OAAO,EAAC,KAAK,IAAI,SAAS,EAAC,MAAM,MAAM,CAAA;AAEvC,OAAO,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAA;AAOpD,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,EAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAC,CAAC,CAAA;AAC1E,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,EAAC,SAAS,EAAE,KAAK,EAAC,CAAC,CAAA;AAIlC,MAAM,OAAO,WAAW;IACtB,OAAO,CAAQ;IACf,IAAI,CAAQ;IACZ,QAAQ,CAAiB;IACzB,YAAY,CAAS;IACrB,GAAG,CAAY;IAEf,YAAY,IAA8D;QACxE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAA2B,CAAA;QAChD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAA;QACjC,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAC1E,IAAI,CAAC,IAAI,GAAG,EAAE,CAAA;QAChB,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACjC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC;iBACf,OAAO,EAAE;iBACT,GAAG,CAAC,EAAE,CAAC,EAAE;gBACR,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAA;gBACjB,OAAO;oBACL,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;oBACxB,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;iBACjB,CAAA;YACH,CAAC,CAAC,CAAA;QACN,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,GAAG,EAAE,CAAA;QACf,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,OAAe;QACzB,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACzC,MAAM,EAAC,IAAI,EAAE,QAAQ,EAAC,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAA;QAC/C,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAoB,CAAA;QACvD,OAAO,IAAI,WAAW,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAC,CAAC,CAAA;IACnD,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"article-not-found.d.ts","sourceRoot":"","sources":["../../src/lib/article-not-found.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAA;AAM1D,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAcjB"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { articleUrlMatches, getDevcenterBaseUrl, searchApiPath } from './paths.js';
|
|
2
|
+
export async function formatArticleNotFoundMessage(client, slug) {
|
|
3
|
+
const baseUrl = getDevcenterBaseUrl();
|
|
4
|
+
const { body } = await client.getJson(searchApiPath(), { query: slug });
|
|
5
|
+
const results = (body?.results ?? []).filter(r => articleUrlMatches(r.full_url, baseUrl));
|
|
6
|
+
const lines = [`No ${slug} article found.`];
|
|
7
|
+
if (results.length > 0) {
|
|
8
|
+
lines.push('Perhaps you meant one of these:');
|
|
9
|
+
const longest = Math.max(...results.map(r => r.slug.length));
|
|
10
|
+
for (const s of results) {
|
|
11
|
+
lines.push(`${s.slug.padEnd(longest)} # ${s.title}`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return lines.join('\n');
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=article-not-found.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"article-not-found.js","sourceRoot":"","sources":["../../src/lib/article-not-found.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,iBAAiB,EAAE,mBAAmB,EAAE,aAAa,EAAC,MAAM,YAAY,CAAA;AAIhF,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,MAAuB,EACvB,IAAY;IAEZ,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAA;IACrC,MAAM,EAAC,IAAI,EAAC,GAAG,MAAM,MAAM,CAAC,OAAO,CAA4B,aAAa,EAAE,EAAE,EAAC,KAAK,EAAE,IAAI,EAAC,CAAC,CAAA;IAC9F,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;IACzF,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,iBAAiB,CAAC,CAAA;IAC3C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAA;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;QAC5D,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
|