zuplo 7.13.3 → 7.13.5
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/docs/articles/api-lint-breaking-changes.mdx +211 -0
- package/docs/articles/api-lint-ci-cd.mdx +242 -0
- package/docs/articles/api-lint-configuration.mdx +459 -0
- package/docs/articles/api-lint-custom-rules.mdx +222 -0
- package/docs/articles/api-lint-rules.mdx +360 -0
- package/docs/articles/api-lint.mdx +267 -0
- package/docs/cli/lint.mdx +64 -0
- package/docs/cli/lint.partial.mdx +70 -0
- package/docs/dev-portal/zudoku/configuration/api-catalog.md +16 -0
- package/docs/dev-portal/zudoku/configuration/blog.md +217 -0
- package/package.json +5 -5
package/docs/cli/lint.mdx
CHANGED
|
@@ -96,6 +96,61 @@ applies_to:
|
|
|
96
96
|
usage="$0 lint [options]"
|
|
97
97
|
>
|
|
98
98
|
|
|
99
|
+
`zuplo lint` checks the OpenAPI files in your project's `config/` directory and
|
|
100
|
+
`config/policies.json` for missing fields, undefined policies, invalid policy
|
|
101
|
+
options, and Zuplo conventions. It runs locally and doesn't need an API key. See
|
|
102
|
+
[Linting your API](../articles/api-lint.mdx) for an overview of what it checks.
|
|
103
|
+
|
|
104
|
+
The command reads its settings from `zuplo.lint.jsonc` (or `zuplo.lint.json`)
|
|
105
|
+
in the project directory.
|
|
106
|
+
See [Lint configuration](../articles/api-lint-configuration.mdx) for presets,
|
|
107
|
+
rule severities, required policies, and breaking change detection.
|
|
108
|
+
|
|
109
|
+
## Exit codes
|
|
110
|
+
|
|
111
|
+
| Code | Meaning |
|
|
112
|
+
| ---- | --------------------------------------------------------------------------------------------------- |
|
|
113
|
+
| `0` | No results at or above the failure threshold. |
|
|
114
|
+
| `1` | The linter found results at or above the failure threshold. |
|
|
115
|
+
| `2` | The linter couldn't run: the directory isn't a Zuplo project, or the configuration file is invalid. |
|
|
116
|
+
|
|
117
|
+
## Common use cases
|
|
118
|
+
|
|
119
|
+
### Lint before you commit
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npx zuplo lint
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Apply automatic fixes
|
|
126
|
+
|
|
127
|
+
`--fix` adds missing `operationId` values and removes empty inbound policy
|
|
128
|
+
arrays, then reports what's left. See
|
|
129
|
+
[Fix problems automatically](../articles/api-lint.mdx#fix-problems-automatically).
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx zuplo lint --fix
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### List the rules you can use
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npx zuplo lint --list-rules
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Add `--format json` for machine-readable output.
|
|
142
|
+
|
|
143
|
+
### Lint in CI
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npx zuplo lint --format sarif > zuplo-lint.sarif
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
See [Lint in CI/CD](../articles/api-lint-ci-cd.mdx) for GitHub Actions
|
|
150
|
+
workflows, including code scanning, and
|
|
151
|
+
[Breaking change detection](../articles/api-lint-breaking-changes.mdx) for
|
|
152
|
+
comparing your API against a Git branch.
|
|
153
|
+
|
|
99
154
|
</CliCommand>
|
|
100
155
|
|
|
101
156
|
## Global options
|
|
@@ -104,3 +159,12 @@ The following global options are available for all commands:
|
|
|
104
159
|
|
|
105
160
|
- [`--help`](./global-options.mdx#help)
|
|
106
161
|
- [`--api-key`](./global-options.mdx#api-key)
|
|
162
|
+
|
|
163
|
+
## Additional resources
|
|
164
|
+
|
|
165
|
+
- [Linting your API](../articles/api-lint.mdx)
|
|
166
|
+
- [Lint configuration](../articles/api-lint-configuration.mdx)
|
|
167
|
+
- [Lint rules reference](../articles/api-lint-rules.mdx)
|
|
168
|
+
- [Lint in CI/CD](../articles/api-lint-ci-cd.mdx)
|
|
169
|
+
- [Custom lint rules](../articles/api-lint-custom-rules.mdx)
|
|
170
|
+
- [Breaking change detection](../articles/api-lint-breaking-changes.mdx)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
additional-resources:
|
|
3
|
+
- name: Linting your API
|
|
4
|
+
href: ../articles/api-lint.mdx
|
|
5
|
+
- name: Lint configuration
|
|
6
|
+
href: ../articles/api-lint-configuration.mdx
|
|
7
|
+
- name: Lint rules reference
|
|
8
|
+
href: ../articles/api-lint-rules.mdx
|
|
9
|
+
- name: Lint in CI/CD
|
|
10
|
+
href: ../articles/api-lint-ci-cd.mdx
|
|
11
|
+
- name: Custom lint rules
|
|
12
|
+
href: ../articles/api-lint-custom-rules.mdx
|
|
13
|
+
- name: Breaking change detection
|
|
14
|
+
href: ../articles/api-lint-breaking-changes.mdx
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
`zuplo lint` checks the OpenAPI files in your project's `config/` directory and
|
|
18
|
+
`config/policies.json` for missing fields, undefined policies, invalid policy
|
|
19
|
+
options, and Zuplo conventions. It runs locally and doesn't need an API key. See
|
|
20
|
+
[Linting your API](../articles/api-lint.mdx) for an overview of what it checks.
|
|
21
|
+
|
|
22
|
+
The command reads its settings from `zuplo.lint.jsonc` (or `zuplo.lint.json`)
|
|
23
|
+
in the project directory.
|
|
24
|
+
See [Lint configuration](../articles/api-lint-configuration.mdx) for presets,
|
|
25
|
+
rule severities, required policies, and breaking change detection.
|
|
26
|
+
|
|
27
|
+
## Exit codes
|
|
28
|
+
|
|
29
|
+
| Code | Meaning |
|
|
30
|
+
| ---- | --------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| `0` | No results at or above the failure threshold. |
|
|
32
|
+
| `1` | The linter found results at or above the failure threshold. |
|
|
33
|
+
| `2` | The linter couldn't run: the directory isn't a Zuplo project, or the configuration file is invalid. |
|
|
34
|
+
|
|
35
|
+
## Common use cases
|
|
36
|
+
|
|
37
|
+
### Lint before you commit
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx zuplo lint
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Apply automatic fixes
|
|
44
|
+
|
|
45
|
+
`--fix` adds missing `operationId` values and removes empty inbound policy
|
|
46
|
+
arrays, then reports what's left. See
|
|
47
|
+
[Fix problems automatically](../articles/api-lint.mdx#fix-problems-automatically).
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx zuplo lint --fix
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### List the rules you can use
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx zuplo lint --list-rules
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Add `--format json` for machine-readable output.
|
|
60
|
+
|
|
61
|
+
### Lint in CI
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx zuplo lint --format sarif > zuplo-lint.sarif
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
See [Lint in CI/CD](../articles/api-lint-ci-cd.mdx) for GitHub Actions
|
|
68
|
+
workflows, including code scanning, and
|
|
69
|
+
[Breaking change detection](../articles/api-lint-breaking-changes.mdx) for
|
|
70
|
+
comparing your API against a Git branch.
|
|
@@ -9,6 +9,22 @@ applies_to:
|
|
|
9
9
|
If you're dealing with multiple APIs and multiple OpenAPI files, the API Catalog comes in handy. It
|
|
10
10
|
creates an overview of all your APIs and lets you organize them into categories and tags.
|
|
11
11
|
|
|
12
|
+
## Categories and Tags
|
|
13
|
+
|
|
14
|
+
Each entry in an API's `categories` array has two fields, `label` and `tags`, which serve different
|
|
15
|
+
purposes:
|
|
16
|
+
|
|
17
|
+
- **`label`** is the primary grouping. The catalog page renders one filter chip per unique label, so
|
|
18
|
+
this is what users click to narrow the list. An API can belong to multiple categories by adding
|
|
19
|
+
multiple entries to the array.
|
|
20
|
+
- **`tags`** are secondary descriptors attached to that category. They do _not_ get their own filter
|
|
21
|
+
chip. Instead, they are matched against the search input and rendered as additional badges on the
|
|
22
|
+
API card (alongside the label). Use them for finer-grained keywords that should help users
|
|
23
|
+
discover an API without cluttering the top-level filters.
|
|
24
|
+
|
|
25
|
+
For example, `{ label: "Payments", tags: ["billing", "subscriptions"] }` puts the API under the
|
|
26
|
+
"Payments" filter chip and adds "billing" and "subscriptions" as searchable badges on its card.
|
|
27
|
+
|
|
12
28
|
## Enable API Catalog
|
|
13
29
|
|
|
14
30
|
To enable the API Catalog, add a `catalogs` object to your Dev Portal configuration file.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Blog
|
|
3
|
+
navigation_icon: newspaper
|
|
4
|
+
applies_to:
|
|
5
|
+
product: developer-portal
|
|
6
|
+
hosting: all
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Dev Portal can publish a blog next to your documentation and API reference. Posts are Markdown or MDX
|
|
10
|
+
files in a folder of your project: add a file and it shows up in the blog, with a paginated index,
|
|
11
|
+
tag pages, a "Recent posts" sidebar and an RSS feed.
|
|
12
|
+
|
|
13
|
+
:::caution{title="Beta"}
|
|
14
|
+
|
|
15
|
+
The blog plugin is in beta. Its options, frontmatter fields and generated URLs may still change in a
|
|
16
|
+
minor release. Feedback is welcome in [GitHub issues](https://github.com/zuplo/zudoku/issues).
|
|
17
|
+
|
|
18
|
+
:::
|
|
19
|
+
|
|
20
|
+
## Enable the blog
|
|
21
|
+
|
|
22
|
+
Add the blog plugin to the `plugins` of your config. Every option has a default:
|
|
23
|
+
|
|
24
|
+
```tsx title="zudoku.config.tsx"
|
|
25
|
+
import { blogPlugin } from "zudoku/plugins/blog";
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
plugins: [blogPlugin()],
|
|
29
|
+
};
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Then put your posts in the `blog` folder at the root of your project:
|
|
33
|
+
|
|
34
|
+
```text title="File tree"
|
|
35
|
+
blog/
|
|
36
|
+
├── 2025-03-14-hello-world.md → /blog/hello-world
|
|
37
|
+
├── 2025-04-02-launch-week/
|
|
38
|
+
│ ├── index.mdx → /blog/launch-week
|
|
39
|
+
│ └── screenshot.png
|
|
40
|
+
└── release-notes/
|
|
41
|
+
└── 2025-05-20-v2.md → /blog/release-notes/v2
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
To link to the blog from the top navigation, add a link to your [navigation](./navigation.mdx):
|
|
45
|
+
|
|
46
|
+
```tsx title="zudoku.config.tsx"
|
|
47
|
+
export default {
|
|
48
|
+
navigation: [
|
|
49
|
+
// ...
|
|
50
|
+
{ type: "link", to: "/blog", label: "Blog", icon: "newspaper" },
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Writing posts
|
|
56
|
+
|
|
57
|
+
The file name sets the URL and the date of a post: a `YYYY-MM-DD-` prefix is the publish date and
|
|
58
|
+
the rest is the slug. A post can also be a folder with an `index.md` or `index.mdx` file, which
|
|
59
|
+
keeps its images next to it. Folders that aren't dated stay part of the URL.
|
|
60
|
+
|
|
61
|
+
Some files are not posts:
|
|
62
|
+
|
|
63
|
+
- Other Markdown files in a post's folder, such as partials imported by its `index.mdx` or a
|
|
64
|
+
`README.md`
|
|
65
|
+
- Files and folders whose name starts with `_`, e.g. `_drafts/` or `_snippet.mdx`
|
|
66
|
+
- Posts whose URL is taken by the blog's own pages: `<path>/tags`, `<path>/tags/*`, `<path>/page/*`
|
|
67
|
+
and `<path>/rss.xml`. These are skipped with a warning.
|
|
68
|
+
|
|
69
|
+
Link to other posts by their file, e.g. `[Launch](./2025-04-02-launch-week/index.mdx)`, and the link
|
|
70
|
+
points to the post's URL.
|
|
71
|
+
|
|
72
|
+
Posts support everything [Markdown and MDX pages](../markdown/overview.md) do, including
|
|
73
|
+
[admonitions](../markdown/admonitions.md), [code blocks](../markdown/code-blocks.md) and React
|
|
74
|
+
components.
|
|
75
|
+
|
|
76
|
+
```md title="blog/2025-03-14-hello-world.md"
|
|
77
|
+
---
|
|
78
|
+
title: Hello World
|
|
79
|
+
description: The first post on our new developer blog.
|
|
80
|
+
authors: [jane]
|
|
81
|
+
tags: [Announcements, API]
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
This paragraph is the excerpt shown on the blog index page.
|
|
85
|
+
|
|
86
|
+
## A section
|
|
87
|
+
|
|
88
|
+
The post continues here.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Frontmatter
|
|
92
|
+
|
|
93
|
+
| Field | Description |
|
|
94
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
95
|
+
| `title` | Title of the post. Defaults to the first `# Heading`, which is then not repeated in the post body. |
|
|
96
|
+
| `description` | Shown on the index page, in the feed and as the meta description. Defaults to the first paragraph. |
|
|
97
|
+
| `date` | Publish date, e.g. `2025-03-14` or `2025-03-14T09:00:00Z`. Defaults to the date in the file name, then the date of the commit that added the file (needs the full git history), then the file's modification time. |
|
|
98
|
+
| `slug` | Overrides the URL: `slug: launch` serves the post at `/blog/launch`. |
|
|
99
|
+
| `authors` | Author keys from [`authors`](#authors), or inline objects such as `{ name: "Jane Doe", title: "Engineer" }`. |
|
|
100
|
+
| `tags` | List of tags. Each tag gets a page listing its posts. |
|
|
101
|
+
| `image` | Image used as `og:image` when the post is shared. An absolute URL or a path in the `public` folder, e.g. `/cover.png`. |
|
|
102
|
+
| `draft` | When `true`, the post is only shown in development. |
|
|
103
|
+
| `toc` | Set to `false` to hide the table of contents. |
|
|
104
|
+
| `seo` | `title` and `description` that override the browser title and meta description only. |
|
|
105
|
+
|
|
106
|
+
Posts are sorted by date, newest first.
|
|
107
|
+
|
|
108
|
+
## Plugin options
|
|
109
|
+
|
|
110
|
+
```tsx title="zudoku.config.tsx"
|
|
111
|
+
import { blogPlugin } from "zudoku/plugins/blog";
|
|
112
|
+
|
|
113
|
+
export default {
|
|
114
|
+
plugins: [
|
|
115
|
+
blogPlugin({
|
|
116
|
+
files: "/blog/**/*.{md,mdx}",
|
|
117
|
+
path: "/blog",
|
|
118
|
+
title: "Blog",
|
|
119
|
+
description: "News and updates from the team.",
|
|
120
|
+
postsPerPage: 10,
|
|
121
|
+
showReadingTime: true,
|
|
122
|
+
authors: {
|
|
123
|
+
jane: {
|
|
124
|
+
name: "Jane Doe",
|
|
125
|
+
title: "Developer Advocate",
|
|
126
|
+
url: "https://example.com/jane",
|
|
127
|
+
imageUrl: "https://example.com/jane.png",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
sidebar: { title: "Recent posts", count: 5 },
|
|
131
|
+
feed: true,
|
|
132
|
+
}),
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `files`
|
|
138
|
+
|
|
139
|
+
**Type:** `string | string[]`
|
|
140
|
+
**Default:** `"/blog/**/*.{md,mdx}"`
|
|
141
|
+
|
|
142
|
+
Glob patterns for the post files. Keep them outside of [`docs.files`](./docs.md#files) so a post
|
|
143
|
+
isn't also published as a documentation page.
|
|
144
|
+
|
|
145
|
+
### `path`
|
|
146
|
+
|
|
147
|
+
**Type:** `string`
|
|
148
|
+
**Default:** `"/blog"`
|
|
149
|
+
|
|
150
|
+
The route the blog is served under. The index is at `path`, further index pages at `path/page/2`,
|
|
151
|
+
tags at `path/tags` and posts at `path/<slug>`.
|
|
152
|
+
|
|
153
|
+
### `title` and `description`
|
|
154
|
+
|
|
155
|
+
**Type:** `string`
|
|
156
|
+
**Default:** `"Blog"` and none
|
|
157
|
+
|
|
158
|
+
Heading and introduction of the index page. Both are also used for the RSS feed.
|
|
159
|
+
|
|
160
|
+
### `postsPerPage`
|
|
161
|
+
|
|
162
|
+
**Type:** `number`
|
|
163
|
+
**Default:** `10`
|
|
164
|
+
|
|
165
|
+
Number of posts on each page of the index.
|
|
166
|
+
|
|
167
|
+
### `showReadingTime`
|
|
168
|
+
|
|
169
|
+
**Type:** `boolean`
|
|
170
|
+
**Default:** `true`
|
|
171
|
+
|
|
172
|
+
Shows an estimated reading time next to the date of each post.
|
|
173
|
+
|
|
174
|
+
### `authors`
|
|
175
|
+
|
|
176
|
+
**Type:** `Record<string, { name: string; title?: string; url?: string; imageUrl?: string }>`
|
|
177
|
+
**Default:** `{}`
|
|
178
|
+
|
|
179
|
+
Authors that posts reference by key in their `authors` frontmatter, so their details are kept in one
|
|
180
|
+
place. Authors without an `imageUrl` show their initial instead.
|
|
181
|
+
|
|
182
|
+
### `sidebar`
|
|
183
|
+
|
|
184
|
+
**Type:** `{ title?: string; count?: number } | false`
|
|
185
|
+
**Default:** `{ title: "Recent posts", count: 5 }`
|
|
186
|
+
|
|
187
|
+
Lists the most recent posts in the sidebar of all blog pages. Set to `false` to hide it.
|
|
188
|
+
|
|
189
|
+
### `feed`
|
|
190
|
+
|
|
191
|
+
**Type:** `boolean`
|
|
192
|
+
**Default:** on when a site URL is configured
|
|
193
|
+
|
|
194
|
+
Generates an RSS feed at `<path>/rss.xml` and links it from every blog page. Feeds need absolute
|
|
195
|
+
links, so the site URL is taken from [`canonicalUrlOrigin`](./overview.md#canonicalurlorigin) or
|
|
196
|
+
[`sitemap.siteUrl`](./overview.md#sitemap). Without either, no feed is generated.
|
|
197
|
+
|
|
198
|
+
## Multiple blogs
|
|
199
|
+
|
|
200
|
+
Add the plugin once per blog, each with its own `files` and `path`, for example a blog and a
|
|
201
|
+
changelog:
|
|
202
|
+
|
|
203
|
+
```tsx title="zudoku.config.tsx"
|
|
204
|
+
import { blogPlugin } from "zudoku/plugins/blog";
|
|
205
|
+
|
|
206
|
+
export default {
|
|
207
|
+
plugins: [
|
|
208
|
+
blogPlugin({ files: "/blog/**/*.{md,mdx}", path: "/blog" }),
|
|
209
|
+
blogPlugin({
|
|
210
|
+
files: "/changelog/**/*.{md,mdx}",
|
|
211
|
+
path: "/changelog",
|
|
212
|
+
title: "Changelog",
|
|
213
|
+
sidebar: false,
|
|
214
|
+
}),
|
|
215
|
+
],
|
|
216
|
+
};
|
|
217
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zuplo",
|
|
3
|
-
"version": "7.13.
|
|
3
|
+
"version": "7.13.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The official Zuplo CLI for local development and platform management",
|
|
6
6
|
"homepage": "https://zuplo.com/docs/cli/overview",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"zuplo": "zuplo.js"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@zuplo/cli": "7.13.
|
|
36
|
-
"@zuplo/core": "7.13.
|
|
37
|
-
"@zuplo/runtime": "7.13.
|
|
38
|
-
"@zuplo/test": "7.13.
|
|
35
|
+
"@zuplo/cli": "7.13.5",
|
|
36
|
+
"@zuplo/core": "7.13.5",
|
|
37
|
+
"@zuplo/runtime": "7.13.5",
|
|
38
|
+
"@zuplo/test": "7.13.5"
|
|
39
39
|
}
|
|
40
40
|
}
|