openapi-import 0.0.1 → 0.0.3
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/README.md +86 -43
- package/dist/server.js +100 -29
- package/dist/server.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,37 +1,33 @@
|
|
|
1
1
|
# openapi-import
|
|
2
2
|
|
|
3
|
-
Import an OpenAPI spec in TypeScript and get
|
|
3
|
+
Import an OpenAPI spec in TypeScript and get types for it, without generating any files.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
|
-
import {
|
|
6
|
+
import type { Pet } from './petStore.openapi.yaml'
|
|
7
|
+
|
|
8
|
+
const pet: Pet = { name: 'Rex', photoUrls: [], status: 'available' }
|
|
7
9
|
```
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
Autocomplete, type errors and go to definition come straight from the spec. When the spec changes, the types change with it.
|
|
10
12
|
|
|
11
13
|
> [!WARNING]
|
|
12
|
-
> Experimental. It needs TypeScript 7.1.0-beta or later
|
|
14
|
+
> Experimental. It needs TypeScript 7.1.0-beta or later, which adds [content mappers](https://github.com/microsoft/typescript-go/pull/4712): packages that tell the compiler how to read a file type it does not know.
|
|
13
15
|
|
|
14
|
-
##
|
|
16
|
+
## Why
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
- Autocomplete and type errors come from the spec.
|
|
20
|
-
- Go to definition, find references and hover jump between the types and the spec.
|
|
21
|
-
- Rename a schema type in TypeScript and the key in the spec is renamed too.
|
|
22
|
-
- Spec errors, such as an unresolved `$ref`, show on the key they point at.
|
|
23
|
-
- `tsc --runExternalCode` reports the same errors in CI.
|
|
24
|
-
- At run time, `unplugin-kubb` loads the same module in Vite, webpack, Rollup and other bundlers.
|
|
18
|
+
Most projects turn an OpenAPI spec into TypeScript with a code generator. You run it every time the spec changes, decide whether to commit the output, and land in generated code when you go to definition.
|
|
19
|
+
|
|
20
|
+
`openapi-import` skips that step. The spec is the module you import, so there is nothing to regenerate, and the editor links every type back to its key in the spec.
|
|
25
21
|
|
|
26
|
-
##
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
Install it with Kubb, which generates the types, and the TypeScript beta:
|
|
27
25
|
|
|
28
26
|
```bash
|
|
29
|
-
pnpm add -D
|
|
27
|
+
pnpm add -D openapi-import kubb typescript@beta
|
|
30
28
|
```
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Register the `.openapi.yaml` extension in `tsconfig.json`. A plain `.yaml` would also send files such as `docker-compose.yaml` to the mapper, and `.json` can't be mapped.
|
|
30
|
+
Register the mapper in `tsconfig.json`:
|
|
35
31
|
|
|
36
32
|
```json
|
|
37
33
|
{
|
|
@@ -39,36 +35,27 @@ Register the `.openapi.yaml` extension in `tsconfig.json`. A plain `.yaml` would
|
|
|
39
35
|
}
|
|
40
36
|
```
|
|
41
37
|
|
|
42
|
-
|
|
38
|
+
Name your spec `<name>.openapi.yaml`, such as `petStore.openapi.yaml`, and import from it:
|
|
43
39
|
|
|
44
40
|
```ts
|
|
45
|
-
import {
|
|
46
|
-
import { pluginZod } from '@kubb/plugin-zod'
|
|
47
|
-
import { defineConfig } from 'kubb/config'
|
|
48
|
-
|
|
49
|
-
export default defineConfig({
|
|
50
|
-
output: { path: './src/gen' },
|
|
51
|
-
plugins: [pluginTs(), pluginZod()],
|
|
52
|
-
})
|
|
41
|
+
import type { GetPetByIdPath, GetPetByIdResponse, Pet } from './petStore.openapi.yaml'
|
|
53
42
|
```
|
|
54
43
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
For values at run time, add `kubb()` from `kubb/vite` or another bundler entry, without a `config` option, so it reads the same `kubb.config.ts` as `tsc`. A config with an `input` also writes the generated files at build time, so leave it out to import specs only.
|
|
58
|
-
|
|
59
|
-
Run the type check:
|
|
44
|
+
Run the type check. TypeScript runs the mapper only with `--runExternalCode`:
|
|
60
45
|
|
|
61
46
|
```bash
|
|
62
47
|
tsc --noEmit --runExternalCode
|
|
63
48
|
```
|
|
64
49
|
|
|
65
|
-
VS Code only passes `--runExternalCode` in trusted workspaces.
|
|
50
|
+
With npm, `tsc` runs TypeScript 6. Run `node node_modules/typescript/bin/tsc` instead. VS Code only passes `--runExternalCode` in trusted workspaces.
|
|
66
51
|
|
|
67
|
-
|
|
52
|
+
[`examples/pet-store`](./examples/pet-store) has a working setup.
|
|
53
|
+
|
|
54
|
+
## What you can import
|
|
68
55
|
|
|
69
|
-
|
|
56
|
+
Each schema and operation in the spec becomes a type. Schema types keep the name of their key in the spec:
|
|
70
57
|
|
|
71
|
-
|
|
|
58
|
+
| Import | Comes from |
|
|
72
59
|
| ------------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
73
60
|
| `Pet` | `components.schemas.Pet` |
|
|
74
61
|
| `Pet['name']` | `properties.name` under `Pet`, nested objects and arrays of them included |
|
|
@@ -78,18 +65,74 @@ Go to definition, find references and hover link generated names to their keys i
|
|
|
78
65
|
| `GetPetByIdStatus404` | `responses.404` |
|
|
79
66
|
| `AddPetBody` | the operation's `requestBody` |
|
|
80
67
|
|
|
81
|
-
|
|
68
|
+
## Editor support
|
|
69
|
+
|
|
70
|
+
- Hover, go to definition and find references jump from each name in the table to its key in the spec.
|
|
71
|
+
- Renaming a schema type renames its key in the spec, and the `$ref`s on a property, an array item or a schema alias that point at it. Update other `$ref`s, such as inside `allOf` or a response, yourself.
|
|
72
|
+
- Spec errors, such as an unresolved `$ref`, show on the key they point at.
|
|
73
|
+
- `tsc --runExternalCode` reports the same errors in CI.
|
|
74
|
+
|
|
75
|
+
## Add Zod schemas and more
|
|
76
|
+
|
|
77
|
+
Add a `kubb.config.ts` to get more than types from the same import, such as Zod schemas from `@kubb/plugin-zod`. Any [Kubb plugin](https://kubb.dev/extensions/kind/plugins) works. List `pluginTs()` too, to keep the types:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pnpm add -D @kubb/plugin-ts @kubb/plugin-zod
|
|
81
|
+
pnpm add zod
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
// kubb.config.ts
|
|
86
|
+
import { pluginTs } from '@kubb/plugin-ts'
|
|
87
|
+
import { pluginZod } from '@kubb/plugin-zod'
|
|
88
|
+
import { defineConfig } from 'kubb/config'
|
|
89
|
+
|
|
90
|
+
export default defineConfig({
|
|
91
|
+
output: { path: './src/gen' },
|
|
92
|
+
plugins: [pluginTs(), pluginZod()],
|
|
93
|
+
})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Put the config next to `tsconfig.json` or in a parent folder. The editor picks up changes to it. With several configs, a spec uses the one whose `input` points at it.
|
|
97
|
+
|
|
98
|
+
## Use values at run time
|
|
99
|
+
|
|
100
|
+
`tsc` only checks types and does not emit the spec as JavaScript. Values such as `petSchema` need your bundler to load the spec. Add `kubb()` from `kubb/vite`, `kubb/webpack`, `kubb/rollup` or another entry, without a `config` option, so it reads the same `kubb.config.ts`:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
// vite.config.ts
|
|
104
|
+
import kubb from 'kubb/vite'
|
|
105
|
+
import { defineConfig } from 'vite'
|
|
106
|
+
|
|
107
|
+
export default defineConfig({
|
|
108
|
+
plugins: [kubb()],
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The types and the values then come from the same import:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { type GetPetByIdPath, type GetPetByIdResponse, petSchema } from './petStore.openapi.yaml'
|
|
116
|
+
|
|
117
|
+
export async function getPetById({ petId }: GetPetByIdPath): Promise<GetPetByIdResponse> {
|
|
118
|
+
const response = await fetch(`https://petstore3.swagger.io/api/v3/pet/${petId}`)
|
|
119
|
+
|
|
120
|
+
return petSchema.parse(await response.json())
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Leave `input` out of the config to import specs only. With an `input`, the bundler also writes the generated files at build time. Restart the bundler after you change the config.
|
|
82
125
|
|
|
83
126
|
## Limits
|
|
84
127
|
|
|
85
|
-
- Code a plugin writes to a separate file, such as a bundled client runtime, is not included. Point imports like
|
|
86
|
-
- Properties of operation types don't link to the spec, and renaming
|
|
128
|
+
- Code a plugin writes to a separate file, such as a bundled client runtime, is not included. Point imports like a client's `importPath` at a package.
|
|
129
|
+
- Properties of operation types don't link to the spec, and renaming one doesn't rename its key.
|
|
87
130
|
- Files that `kubb.config.ts` imports are not watched. Restart the TypeScript server after you change them.
|
|
88
|
-
- A changed spec
|
|
131
|
+
- A changed spec rebuilds all of its types: about 0.4 s for a 10 KB spec and 2.6 s for a 1.4 MB spec.
|
|
89
132
|
|
|
90
|
-
##
|
|
133
|
+
## Sponsors
|
|
91
134
|
|
|
92
|
-
|
|
135
|
+
`openapi-import` is part of [Kubb](https://kubb.dev), an open source project funded entirely by sponsors. If you would like to support it:
|
|
93
136
|
|
|
94
137
|
- [Become a Sponsor on GitHub](https://github.com/sponsors/stijnvanhulle)
|
|
95
138
|
|
package/dist/server.js
CHANGED
|
@@ -2,11 +2,11 @@ import { dirname, resolve } from "node:path";
|
|
|
2
2
|
import { configFileCandidates, findConfigFile, generateModule, loadConfigFile, selectConfig } from "unplugin-kubb";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { readFileSync } from "node:fs";
|
|
5
|
+
import ts from "@typescript/typescript6";
|
|
5
6
|
import { Hookable } from "kubb/kit";
|
|
6
|
-
import { pluginTs } from "@kubb/plugin-ts";
|
|
7
|
+
import { pluginTs, pluginTsName, resolverTs } from "@kubb/plugin-ts";
|
|
7
8
|
import * as yaml from "yaml";
|
|
8
9
|
import { parseDocument } from "yaml";
|
|
9
|
-
import ts from "@typescript/typescript6";
|
|
10
10
|
//#region src/cache.ts
|
|
11
11
|
/**
|
|
12
12
|
* Wraps a transform so a repeated request for the same file, content and config returns the
|
|
@@ -48,7 +48,10 @@ async function loadProjectConfig(dir) {
|
|
|
48
48
|
try {
|
|
49
49
|
return {
|
|
50
50
|
dir,
|
|
51
|
-
configs: await loadConfigFile(
|
|
51
|
+
configs: await loadConfigFile({
|
|
52
|
+
file,
|
|
53
|
+
cli: {}
|
|
54
|
+
}),
|
|
52
55
|
watchedFiles,
|
|
53
56
|
identity
|
|
54
57
|
};
|
|
@@ -105,10 +108,11 @@ const toRange = ([start, end]) => ({
|
|
|
105
108
|
});
|
|
106
109
|
const unescapeToken = (token) => token.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
107
110
|
/**
|
|
108
|
-
* Walks a JSON pointer through maps and sequences; the range is the last key or item it reached
|
|
111
|
+
* Walks a JSON pointer through maps and sequences; the range is the last key or item it reached,
|
|
112
|
+
* or with `value` the scalar value of that key.
|
|
109
113
|
*/
|
|
110
|
-
function findPointer(document, pointer) {
|
|
111
|
-
|
|
114
|
+
function findPointer(document, pointer, value = false) {
|
|
115
|
+
const reached = pointer.replace(/^#/, "").split("/").slice(1).map(unescapeToken).reduce((at, token) => {
|
|
112
116
|
if (yaml.isMap(at?.node)) {
|
|
113
117
|
const pair = at.node.items.find((item) => yaml.isScalar(item.key) && String(item.key.value) === token);
|
|
114
118
|
return pair && yaml.isScalar(pair.key) && pair.key.range ? {
|
|
@@ -126,7 +130,9 @@ function findPointer(document, pointer) {
|
|
|
126
130
|
}, {
|
|
127
131
|
node: document.contents,
|
|
128
132
|
range: void 0
|
|
129
|
-
})
|
|
133
|
+
});
|
|
134
|
+
if (!value) return reached?.range;
|
|
135
|
+
return yaml.isScalar(reached?.node) && reached.node.range ? toRange(reached.node.range) : void 0;
|
|
130
136
|
}
|
|
131
137
|
/**
|
|
132
138
|
* The first `$ref` whose value is `ref`.
|
|
@@ -146,13 +152,14 @@ function findRefUsage(document, ref) {
|
|
|
146
152
|
* the spec on every transform. An unresolved `$ref` falls back to its first usage.
|
|
147
153
|
*/
|
|
148
154
|
function createLocator(document) {
|
|
149
|
-
return ({ pointer, ref }) => findPointer(document, pointer) ?? (ref ? findRefUsage(document, ref) : void 0);
|
|
155
|
+
return ({ pointer, ref, value }) => findPointer(document, pointer, value) ?? (ref ? findRefUsage(document, ref) : void 0);
|
|
150
156
|
}
|
|
151
157
|
//#endregion
|
|
152
158
|
//#region src/mappings.ts
|
|
153
159
|
const kindVerbatim = 0;
|
|
154
160
|
const kindAlias = 2;
|
|
155
161
|
const features = 249;
|
|
162
|
+
const refPrefix = "#/components/schemas/";
|
|
156
163
|
const escapeToken = (token) => token.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
157
164
|
/**
|
|
158
165
|
* Narrows an operation type to the part of the operation it was generated from, by the suffix
|
|
@@ -185,22 +192,24 @@ function declarationPointers(name, { schemas, operations }) {
|
|
|
185
192
|
return [operationPointer(`#/paths/${escapeToken(path)}/${method.toLowerCase()}`, name.slice(operationPrefix.length))];
|
|
186
193
|
}
|
|
187
194
|
/**
|
|
188
|
-
*
|
|
195
|
+
* A property type without `| null` and one level of `T[]` or `Array<T>`, which the spec writes under `items`.
|
|
189
196
|
*/
|
|
190
|
-
function
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (ts.isArrayTypeNode(type) && ts.isTypeLiteralNode(type.elementType)) return {
|
|
197
|
-
node: type.elementType,
|
|
197
|
+
function unwrap(type) {
|
|
198
|
+
const members = type && ts.isUnionTypeNode(type) ? type.types.filter((member) => !(ts.isLiteralTypeNode(member) && member.literal.kind === ts.SyntaxKind.NullKeyword)) : [type];
|
|
199
|
+
const [single] = members.length === 1 ? members : [];
|
|
200
|
+
if (!single) return void 0;
|
|
201
|
+
if (ts.isArrayTypeNode(single)) return {
|
|
202
|
+
type: single.elementType,
|
|
198
203
|
items: true
|
|
199
204
|
};
|
|
200
|
-
if (ts.isTypeReferenceNode(
|
|
201
|
-
|
|
205
|
+
if (ts.isTypeReferenceNode(single) && single.typeName.getText() === "Array" && single.typeArguments?.length === 1) return {
|
|
206
|
+
type: single.typeArguments[0],
|
|
202
207
|
items: true
|
|
203
208
|
};
|
|
209
|
+
return {
|
|
210
|
+
type: single,
|
|
211
|
+
items: false
|
|
212
|
+
};
|
|
204
213
|
}
|
|
205
214
|
/**
|
|
206
215
|
* The members of an interface, or of a type alias for an object literal.
|
|
@@ -212,9 +221,10 @@ function typeMembers(statement) {
|
|
|
212
221
|
/**
|
|
213
222
|
* Links generated names to the spec keys they came from: schemas and their (nested) properties,
|
|
214
223
|
* and operation types to the operation, parameters, request body or response. A schema type named
|
|
215
|
-
* exactly like its key is verbatim, so a rename in TypeScript renames the key.
|
|
224
|
+
* exactly like its key is verbatim, so a rename in TypeScript renames the key. A reference to a
|
|
225
|
+
* schema type maps to the end of the `$ref` that points at that schema, so the rename updates it too.
|
|
216
226
|
*/
|
|
217
|
-
function createMappings(text, content, locate, targets) {
|
|
227
|
+
function createMappings(text, content, { locate, locateValue }, targets) {
|
|
218
228
|
const sourceFile = ts.createSourceFile("index.ts", text, ts.ScriptTarget.Latest, true);
|
|
219
229
|
const segments = [];
|
|
220
230
|
const add = (name, rename, ...pointers) => {
|
|
@@ -230,13 +240,32 @@ function createMappings(text, content, locate, targets) {
|
|
|
230
240
|
verbatim ? 505 : features
|
|
231
241
|
]);
|
|
232
242
|
};
|
|
243
|
+
const addRef = (inner, pointer) => {
|
|
244
|
+
if (!inner || !ts.isTypeReferenceNode(inner.type) || !ts.isIdentifier(inner.type.typeName)) return;
|
|
245
|
+
const reference = inner.type.typeName;
|
|
246
|
+
const name = reference.text;
|
|
247
|
+
if (!targets.schemas.has(name)) return;
|
|
248
|
+
const range = locateValue(`${pointer}${inner.items ? "/items" : ""}/$ref`);
|
|
249
|
+
if (!range) return;
|
|
250
|
+
const start = range.start + content.slice(range.start, range.end).replace(/['"]$/, "").length - name.length;
|
|
251
|
+
if (content.slice(start - 21, start + name.length) !== refPrefix + name) return;
|
|
252
|
+
segments.push([
|
|
253
|
+
reference.getStart(sourceFile),
|
|
254
|
+
reference.getWidth(sourceFile),
|
|
255
|
+
start,
|
|
256
|
+
name.length,
|
|
257
|
+
kindVerbatim,
|
|
258
|
+
505
|
|
259
|
+
]);
|
|
260
|
+
};
|
|
233
261
|
const addMembers = (members, pointer) => {
|
|
234
262
|
for (const member of members) {
|
|
235
263
|
if (!ts.isPropertySignature(member) || !(ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))) continue;
|
|
236
264
|
const propertyPointer = `${pointer}/properties/${escapeToken(member.name.text)}`;
|
|
237
265
|
add(member.name, false, propertyPointer);
|
|
238
|
-
const
|
|
239
|
-
|
|
266
|
+
const inner = unwrap(member.type);
|
|
267
|
+
addRef(inner, propertyPointer);
|
|
268
|
+
if (inner && ts.isTypeLiteralNode(inner.type)) addMembers(inner.type.members, inner.items ? `${propertyPointer}/items` : propertyPointer);
|
|
240
269
|
}
|
|
241
270
|
};
|
|
242
271
|
for (const statement of sourceFile.statements) {
|
|
@@ -256,11 +285,41 @@ function createMappings(text, content, locate, targets) {
|
|
|
256
285
|
if (!pointer || !isSchema) continue;
|
|
257
286
|
const members = typeMembers(statement);
|
|
258
287
|
if (members) addMembers(members, pointer);
|
|
288
|
+
else if (ts.isTypeAliasDeclaration(statement)) addRef(unwrap(statement.type), pointer);
|
|
259
289
|
}
|
|
260
290
|
return segments;
|
|
261
291
|
}
|
|
262
292
|
//#endregion
|
|
263
293
|
//#region src/transform.ts
|
|
294
|
+
const scanner = ts.createScanner(ts.ScriptTarget.Latest, true);
|
|
295
|
+
function isPlainIdentifier(name) {
|
|
296
|
+
scanner.setText(name);
|
|
297
|
+
return scanner.scan() === ts.SyntaxKind.Identifier && scanner.getTokenEnd() === name.length;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Keeps a name that is already a valid type name as the spec wrote it (`pet`, `PET_STATUS`), so a
|
|
301
|
+
* schema type matches its key and renames it. Composed names such as `getPetById Status 200` and
|
|
302
|
+
* keys that are not identifiers keep the `@kubb/plugin-ts` PascalCase.
|
|
303
|
+
*/
|
|
304
|
+
const specName = (name) => isPlainIdentifier(name) ? name : resolverTs.name(name);
|
|
305
|
+
/**
|
|
306
|
+
* Lets `@kubb/plugin-ts` name schema types after their spec keys, unless the config sets its own `resolver.name`.
|
|
307
|
+
*/
|
|
308
|
+
function keepSpecCasing(config) {
|
|
309
|
+
return {
|
|
310
|
+
...config,
|
|
311
|
+
plugins: config.plugins?.map((plugin) => plugin.name === pluginTsName ? {
|
|
312
|
+
...plugin,
|
|
313
|
+
options: {
|
|
314
|
+
...plugin.options,
|
|
315
|
+
resolver: {
|
|
316
|
+
name: specName,
|
|
317
|
+
...plugin.options?.resolver
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
} : plugin)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
264
323
|
/**
|
|
265
324
|
* Generates the module for one spec with `generateModule` from `unplugin-kubb`, the same one a
|
|
266
325
|
* bundler loads. Without a config, only `@kubb/plugin-ts` runs. The spec text comes from the
|
|
@@ -287,18 +346,20 @@ async function transform({ fileName, content }, config) {
|
|
|
287
346
|
if (node.name) targets.schemas.set(resolver.name(node.name), node.name);
|
|
288
347
|
});
|
|
289
348
|
hooks.hook("kubb:generate:operation", (node, { resolver }) => {
|
|
290
|
-
if ("path" in node && node.path && node.method)
|
|
349
|
+
if (!("path" in node && node.path && node.method)) return;
|
|
350
|
+
const target = {
|
|
291
351
|
path: node.path,
|
|
292
352
|
method: node.method
|
|
293
|
-
}
|
|
353
|
+
};
|
|
354
|
+
targets.operations.set(resolver.name(node.operationId), target).set(resolverTs.name(node.operationId), target);
|
|
294
355
|
});
|
|
295
356
|
const { text, errors } = await generateModule({
|
|
296
357
|
root: dirname(fileName),
|
|
297
358
|
input: document.toJS(),
|
|
298
|
-
config: config ?? {
|
|
359
|
+
config: keepSpecCasing(config ?? {
|
|
299
360
|
output: { path: "." },
|
|
300
361
|
plugins: [pluginTs()]
|
|
301
|
-
},
|
|
362
|
+
}),
|
|
302
363
|
hooks
|
|
303
364
|
});
|
|
304
365
|
const locate = createLocator(document);
|
|
@@ -326,7 +387,13 @@ async function transform({ fileName, content }, config) {
|
|
|
326
387
|
return {
|
|
327
388
|
text,
|
|
328
389
|
extension: ".ts",
|
|
329
|
-
mappings: createMappings(text, content,
|
|
390
|
+
mappings: createMappings(text, content, {
|
|
391
|
+
locate: (pointer) => locate({ pointer }),
|
|
392
|
+
locateValue: (pointer) => locate({
|
|
393
|
+
pointer,
|
|
394
|
+
value: true
|
|
395
|
+
})
|
|
396
|
+
}, targets)
|
|
330
397
|
};
|
|
331
398
|
}
|
|
332
399
|
//#endregion
|
|
@@ -369,7 +436,11 @@ const handlers = {
|
|
|
369
436
|
length: 0
|
|
370
437
|
}]
|
|
371
438
|
};
|
|
372
|
-
return cachedTransform(params, project && selectConfig(
|
|
439
|
+
return cachedTransform(params, project && selectConfig({
|
|
440
|
+
configs: project.configs,
|
|
441
|
+
fileName: params.fileName,
|
|
442
|
+
cwd: project.dir
|
|
443
|
+
}));
|
|
373
444
|
}
|
|
374
445
|
};
|
|
375
446
|
async function handle({ id, method = "", params }) {
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":[],"sources":["../src/cache.ts","../src/config.ts","../src/rpc.ts","../src/locate.ts","../src/mappings.ts","../src/transform.ts","../src/server.ts"],"sourcesContent":["import type { UserConfig } from 'kubb'\nimport type { TransformParams } from './transform.ts'\n\n/**\n * Wraps a transform so a repeated request for the same file, content and config returns the\n * previous result. TypeScript asks again for specs it already transformed (another project, a\n * reload), and a Kubb build of a large spec takes seconds. A failed transform is not kept.\n */\nexport function cacheTransform<TResult>(\n transform: (params: TransformParams, config?: UserConfig) => Promise<TResult>,\n): (params: TransformParams, config?: UserConfig) => Promise<TResult> {\n const results = new Map<string, { content: string; config?: UserConfig; result: Promise<TResult> }>()\n\n return (params, config) => {\n const cached = results.get(params.fileName)\n // A reloaded config is a new object, so comparing by reference catches every config change.\n if (cached && cached.content === params.content && cached.config === config) return cached.result\n\n const result = transform(params, config)\n results.set(params.fileName, { content: params.content, config, result })\n result.catch(() => results.delete(params.fileName))\n return result\n }\n}\n","import { createHash } from 'node:crypto'\nimport { readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { UserConfig } from 'kubb'\nimport { configFileCandidates, findConfigFile, loadConfigFile } from 'unplugin-kubb'\n\n/**\n * A Kubb config found for a TypeScript project, with what TypeScript needs to reload it.\n */\nexport type ProjectConfig = {\n /**\n * The project folder. Kubb resolves a config's `root` and `input` from here.\n */\n dir: string\n /**\n * The configs the file exports, empty when there is no config file.\n */\n configs: Array<UserConfig>\n /**\n * The config file, plus every file the CLI would pick up in `dir`, so adding one reloads too.\n */\n watchedFiles: Array<string>\n /**\n * Changes when the config file changes, so TypeScript transforms its specs again.\n */\n identity: string\n /**\n * Why the config file failed to load. Each transform reports it on the spec.\n */\n error?: string\n}\n\n/**\n * Finds the Kubb config the way the Kubb CLI does, from `dir` up, and loads it. A config that\n * exports a function is called with no CLI options.\n */\nexport async function loadProjectConfig(dir: string): Promise<ProjectConfig> {\n dir = resolve(dir)\n const file = findConfigFile(dir)\n const watchedFiles = [...new Set([...(file ? [file] : []), ...configFileCandidates(dir)])]\n if (!file) return { dir, configs: [], watchedFiles, identity: 'none' }\n\n const identity = createHash('sha256').update(readFileSync(file)).digest('hex')\n try {\n return { dir, configs: await loadConfigFile<UserConfig>(file, {}), watchedFiles, identity }\n } catch (error) {\n return { dir, configs: [], watchedFiles, identity, error: `${file} failed to load: ${error instanceof Error ? error.message : String(error)}` }\n }\n}\n","/**\n * A JSON-RPC 2.0 message as the TypeScript content mapper host sends and expects it.\n */\nexport type Message = {\n id?: number | string\n method?: string\n params?: unknown\n result?: unknown\n error?: { code: number; message: string }\n}\n\nconst separator = '\\r\\n\\r\\n'\n\n/**\n * Frames a message with the LSP base protocol `Content-Length` header the host reads.\n */\nexport function encode(message: Message): Buffer {\n const body = Buffer.from(JSON.stringify({ jsonrpc: '2.0', ...message }))\n\n return Buffer.concat([Buffer.from(`Content-Length: ${body.length}${separator}`), body])\n}\n\n/**\n * Returns a stream handler that collects `Content-Length` framed chunks and calls `onMessage`\n * once per complete message, however the chunks split the frames.\n */\nexport function createDecoder(onMessage: (message: Message) => void): (chunk: Buffer) => void {\n let buffer = Buffer.alloc(0)\n\n return (chunk) => {\n buffer = Buffer.concat([buffer, chunk])\n\n while (true) {\n const headerEnd = buffer.indexOf(separator)\n if (headerEnd === -1) return\n\n const header = buffer.subarray(0, headerEnd).toString()\n const length = Number(/content-length:\\s*(\\d+)/i.exec(header)?.[1])\n if (!Number.isInteger(length)) throw new Error(`Missing Content-Length header in \"${header}\"`)\n\n const start = headerEnd + separator.length\n if (buffer.length < start + length) return\n\n const body = buffer.subarray(start, start + length).toString()\n buffer = buffer.subarray(start + length)\n onMessage(JSON.parse(body) as Message)\n }\n }\n}\n","import * as yaml from 'yaml'\n\n/**\n * A range in the spec text, as `[start, end)` offsets.\n */\nexport type Range = { start: number; end: number }\n\nconst toRange = ([start, end]: yaml.Range): Range => ({ start, end })\n\nconst unescapeToken = (token: string) => token.replaceAll('~1', '/').replaceAll('~0', '~')\n\n/**\n * Walks a JSON pointer through maps and sequences; the range is the last key or item it reached.\n */\nfunction findPointer(document: yaml.Document, pointer: string): Range | undefined {\n const tokens = pointer.replace(/^#/, '').split('/').slice(1).map(unescapeToken)\n return tokens.reduce<{ node: unknown; range: Range | undefined } | undefined>(\n (at, token) => {\n if (yaml.isMap(at?.node)) {\n const pair = at.node.items.find((item) => yaml.isScalar(item.key) && String(item.key.value) === token)\n return pair && yaml.isScalar(pair.key) && pair.key.range ? { node: pair.value, range: toRange(pair.key.range) } : undefined\n }\n if (yaml.isSeq(at?.node)) {\n const item = at.node.items[Number(token)]\n return yaml.isNode(item) && item.range ? { node: item, range: toRange(item.range) } : undefined\n }\n return undefined\n },\n { node: document.contents, range: undefined },\n )?.range\n}\n\n/**\n * The first `$ref` whose value is `ref`.\n */\nfunction findRefUsage(document: yaml.Document, ref: string): Range | undefined {\n let found: Range | undefined\n yaml.visit(document, {\n Pair(_, { key, value }) {\n if (!yaml.isScalar(key) || key.value !== '$ref' || !yaml.isScalar(value) || value.value !== ref || !value.range) return\n found = toRange(value.range)\n return yaml.visit.BREAK\n },\n })\n return found\n}\n\n/**\n * Maps JSON pointers to ranges in an already parsed spec, the same way `@kubb/adapter-oas`'s\n * `locate` does from the spec text. Reusing the document the build parsed saves a second parse of\n * the spec on every transform. An unresolved `$ref` falls back to its first usage.\n */\nexport function createLocator(document: yaml.Document): (location: { pointer: string; ref?: string }) => Range | undefined {\n return ({ pointer, ref }) => findPointer(document, pointer) ?? (ref ? findRefUsage(document, ref) : undefined)\n}\n","import ts from '@typescript/typescript6'\n\n/**\n * A span map segment in the tuple form TypeScript reads:\n * `[virtualStart, virtualLength, originalStart, originalLength, kind, features]`.\n */\nexport type Segment = [number, number, number, number, number, number]\n\n/**\n * What the build saw, keyed by the names `@kubb/plugin-ts` emitted.\n */\nexport type Targets = {\n /**\n * Emitted type name to the `components.schemas` key it came from.\n */\n schemas: Map<string, string>\n /**\n * Emitted operation name prefix (such as `GetPetById`) to its path and method.\n */\n operations: Map<string, { path: string; method: string }>\n}\n\ntype Locate = (pointer: string) => { start: number; end: number } | undefined\n\nconst kindVerbatim = 0\nconst kindAlias = 2\n// Hover, Definition, TypeDefinition, Implementation, References, DocumentHighlights.\nconst features = 1 | 8 | 16 | 32 | 64 | 128\n// Only schema names rename into the spec. A stale `$ref` shows as an error, but a stale `required` entry fails silently.\nconst renameFeature = 256\n\nconst escapeToken = (token: string) => token.replaceAll('~', '~0').replaceAll('/', '~1')\n\n/**\n * Narrows an operation type to the part of the operation it was generated from, by the suffix\n * `@kubb/plugin-ts` appends to the operation name.\n */\nfunction operationPointer(base: string, suffix: string): string {\n const status = /^Status(\\d{3}|Default)/.exec(suffix)?.[1]\n if (status) return `${base}/responses/${status === 'Default' ? 'default' : status}`\n if (/^(Path|Query|Header)/.test(suffix)) return `${base}/parameters`\n if (/^(Body|Request|MutationRequest)/.test(suffix)) return `${base}/requestBody`\n return base\n}\n\nconst longestPrefix = (keys: Iterable<string>, name: string) => [...keys].filter((key) => name.startsWith(key)).sort((a, b) => b.length - a.length)[0]\n\n/**\n * Pointers to try for one declaration, most specific first. Enums extracted from a schema property\n * (`OrderStatusEnumKey`, `orderStatusEnum`) point at that property, then at the schema.\n */\nfunction declarationPointers(name: string, { schemas, operations }: Targets): Array<string> {\n const schema = schemas.get(name)\n if (schema) return [`#/components/schemas/${escapeToken(schema)}`]\n\n const schemaPrefix = longestPrefix(schemas.keys(), name)\n const operationPrefix = longestPrefix(operations.keys(), name)\n\n if (schemaPrefix !== undefined && (operationPrefix === undefined || schemaPrefix.length > operationPrefix.length)) {\n const base = `#/components/schemas/${escapeToken(schemas.get(schemaPrefix)!)}`\n const property = name.slice(schemaPrefix.length).replace(/(Enum)?Key$|Enum$/, '')\n return property ? [`${base}/properties/${escapeToken(property[0]!.toLowerCase() + property.slice(1))}`, base] : [base]\n }\n if (operationPrefix === undefined) return []\n\n const { path, method } = operations.get(operationPrefix)!\n return [operationPointer(`#/paths/${escapeToken(path)}/${method.toLowerCase()}`, name.slice(operationPrefix.length))]\n}\n\n/**\n * The object literal a property type describes, looking through `T[]` and `Array<T>`.\n */\nfunction objectLiteral(type: ts.TypeNode | undefined): { node: ts.TypeLiteralNode; items: boolean } | undefined {\n if (!type) return undefined\n if (ts.isTypeLiteralNode(type)) return { node: type, items: false }\n if (ts.isArrayTypeNode(type) && ts.isTypeLiteralNode(type.elementType)) return { node: type.elementType, items: true }\n if (ts.isTypeReferenceNode(type) && type.typeName.getText() === 'Array' && type.typeArguments?.[0] && ts.isTypeLiteralNode(type.typeArguments[0])) {\n return { node: type.typeArguments[0], items: true }\n }\n return undefined\n}\n\n/**\n * The members of an interface, or of a type alias for an object literal.\n */\nfunction typeMembers(statement: ts.TypeAliasDeclaration | ts.InterfaceDeclaration): ts.NodeArray<ts.TypeElement> | undefined {\n if (ts.isInterfaceDeclaration(statement)) return statement.members\n return ts.isTypeLiteralNode(statement.type) ? statement.type.members : undefined\n}\n\n/**\n * Links generated names to the spec keys they came from: schemas and their (nested) properties,\n * and operation types to the operation, parameters, request body or response. A schema type named\n * exactly like its key is verbatim, so a rename in TypeScript renames the key.\n */\nexport function createMappings(text: string, content: string, locate: Locate, targets: Targets): Array<Segment> {\n const sourceFile = ts.createSourceFile('index.ts', text, ts.ScriptTarget.Latest, true)\n const segments: Array<Segment> = []\n\n const add = (name: ts.Node, rename: boolean, ...pointers: Array<string>) => {\n const range = pointers.map(locate).find(Boolean)\n if (!range) return\n const verbatim = rename && content.slice(range.start, range.end) === name.getText(sourceFile)\n segments.push([\n name.getStart(sourceFile),\n name.getWidth(sourceFile),\n range.start,\n range.end - range.start,\n verbatim ? kindVerbatim : kindAlias,\n verbatim ? features | renameFeature : features,\n ])\n }\n\n const addMembers = (members: ts.NodeArray<ts.TypeElement>, pointer: string) => {\n for (const member of members) {\n if (!ts.isPropertySignature(member) || !(ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))) continue\n const propertyPointer = `${pointer}/properties/${escapeToken(member.name.text)}`\n add(member.name, false, propertyPointer)\n const literal = objectLiteral(member.type)\n if (literal) addMembers(literal.node.members, literal.items ? `${propertyPointer}/items` : propertyPointer)\n }\n }\n\n for (const statement of sourceFile.statements) {\n if (ts.isVariableStatement(statement)) {\n // Enum objects (`export const orderStatusEnum = { ... } as const`) match like their `Key` type.\n for (const declaration of statement.declarationList.declarations) {\n if (!ts.isIdentifier(declaration.name)) continue\n const name = declaration.name.text\n add(declaration.name, false, ...declarationPointers(name, targets), ...declarationPointers(name[0]!.toUpperCase() + name.slice(1), targets))\n }\n continue\n }\n if (!ts.isTypeAliasDeclaration(statement) && !ts.isInterfaceDeclaration(statement)) continue\n const pointers = declarationPointers(statement.name.text, targets)\n const isSchema = targets.schemas.has(statement.name.text)\n add(statement.name, isSchema, ...pointers)\n\n // Property names only resolve under a schema, not under operation parameters or responses.\n const pointer = pointers[0]\n if (!pointer || !isSchema) continue\n const members = typeMembers(statement)\n if (members) addMembers(members, pointer)\n }\n\n return segments\n}\n","import { dirname } from 'node:path'\nimport type { UserConfig } from 'kubb'\nimport { Hookable, type KubbHooks } from 'kubb/kit'\nimport { pluginTs } from '@kubb/plugin-ts'\nimport { generateModule } from 'unplugin-kubb'\nimport { parseDocument } from 'yaml'\nimport { createLocator } from './locate.ts'\nimport { createMappings, type Segment, type Targets } from './mappings.ts'\n\n/**\n * Parameters of the content mapper `transform` request.\n */\nexport type TransformParams = {\n fileName: string\n content: string\n}\n\n/**\n * The module TypeScript checks in place of the spec, and the segments linking it to the spec.\n */\nexport type TransformResult = {\n text: string\n extension: '.ts'\n mappings?: Array<Segment>\n diagnostics?: Array<{ messageText: string; start: number; length: number }>\n}\n\n/**\n * Generates the module for one spec with `generateModule` from `unplugin-kubb`, the same one a\n * bundler loads. Without a config, only `@kubb/plugin-ts` runs. The spec text comes from the\n * request, so unsaved edits are checked too. It is parsed once and shared by the build, the\n * diagnostics and the mappings.\n */\nexport async function transform({ fileName, content }: TransformParams, config?: UserConfig): Promise<TransformResult> {\n const document = parseDocument(content)\n if (document.errors.length) {\n return {\n text: 'export {}',\n extension: '.ts',\n diagnostics: document.errors.map((error) => ({ messageText: error.message, start: error.pos[0], length: error.pos[1] - error.pos[0] })),\n }\n }\n\n const hooks = new Hookable<KubbHooks>()\n const targets: Targets = { schemas: new Map(), operations: new Map() }\n hooks.hook('kubb:generate:schema', (node, { resolver }) => {\n if (node.name) targets.schemas.set(resolver.name(node.name), node.name)\n })\n hooks.hook('kubb:generate:operation', (node, { resolver }) => {\n if ('path' in node && node.path && node.method) targets.operations.set(resolver.name(node.operationId), { path: node.path, method: node.method })\n })\n\n const { text, errors } = await generateModule({\n root: dirname(fileName),\n input: document.toJS(),\n config: config ?? { output: { path: '.' }, plugins: [pluginTs()] },\n hooks,\n })\n\n const locate = createLocator(document)\n\n if (errors.length) {\n return {\n text: 'export {}',\n extension: '.ts',\n diagnostics: errors.map((error) => {\n const range = error.location && 'pointer' in error.location ? locate(error.location) : undefined\n return { messageText: error.message, start: range?.start ?? 0, length: range ? range.end - range.start : 0 }\n }),\n }\n }\n\n if (config && !text) {\n return {\n text: 'export {}',\n extension: '.ts',\n diagnostics: [{ messageText: 'kubb.config.ts generated no code for this spec. Add a plugin such as pluginTs().', start: 0, length: 0 }],\n }\n }\n\n return { text, extension: '.ts', mappings: createMappings(text, content, (pointer) => locate({ pointer }), targets) }\n}\n","import { dirname } from 'node:path'\nimport { selectConfig } from 'unplugin-kubb'\nimport { cacheTransform } from './cache.ts'\nimport { loadProjectConfig, type ProjectConfig } from './config.ts'\nimport { createDecoder, encode, type Message } from './rpc.ts'\nimport { transform, type TransformParams } from './transform.ts'\n\n// stdout carries the protocol, so every other stdout write (any console method, direct writes from\n// Kubb or its plugins) goes to stderr.\nconst writeProtocol = process.stdout.write.bind(process.stdout)\nprocess.stdout.write = process.stderr.write.bind(process.stderr) as typeof process.stdout.write\n\n// The load promise is stored right away, so a transform sent before the load finishes waits for it.\nconst projects = new Map<string, Promise<ProjectConfig>>()\n\nconst cachedTransform = cacheTransform(transform)\n\nconst handlers: Record<string, (params: never) => unknown> = {\n initialize: () => ({ protocolVersion: 1, positionEncoding: 'utf-16', diagnosticSource: 'kubb' }),\n // `dynamicConfig` in package.json: TypeScript watches `watchedFiles` and opens the project again\n // when one changes, then transforms its specs again when `configIdentity` differs.\n openProject: async ({ projectHandle, configFileName, options }: { projectHandle: string; configFileName?: string; options?: unknown }) => {\n const loading = loadProjectConfig(configFileName ? dirname(configFileName) : process.cwd())\n projects.set(projectHandle, loading)\n const project = await loading\n\n return {\n configIdentity: project.identity,\n watchedFiles: project.watchedFiles,\n ...(options != null && { optionDiagnostics: [{ path: [], messageText: 'openapi-import has no options. Set plugin options in kubb.config.ts.' }] }),\n }\n },\n closeProject: ({ projectHandle }: { projectHandle: string }) => {\n projects.delete(projectHandle)\n return null\n },\n transform: async (params: TransformParams & { projectHandle: string }) => {\n const project = await projects.get(params.projectHandle)\n if (project?.error) return { text: 'export {}', extension: '.ts', diagnostics: [{ messageText: project.error, start: 0, length: 0 }] }\n\n return cachedTransform(params, project && selectConfig(project.configs, params.fileName, project.dir))\n },\n}\n\nasync function handle({ id, method = '', params }: Message): Promise<void> {\n const handler = handlers[method]\n if (id === undefined) return\n\n try {\n if (!handler) {\n writeProtocol(encode({ id, error: { code: -32601, message: `Unknown method \"${method}\"` } }))\n return\n }\n const result = await handler(params as never)\n writeProtocol(encode({ id, result: result ?? null }))\n } catch (error) {\n writeProtocol(encode({ id, error: { code: -32603, message: error instanceof Error ? (error.stack ?? error.message) : String(error) } }))\n }\n}\n\nprocess.stdin.on(\n 'data',\n createDecoder((message) => void handle(message)),\n)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","names":[],"sources":["../src/cache.ts","../src/config.ts","../src/rpc.ts","../src/locate.ts","../src/mappings.ts","../src/transform.ts","../src/server.ts"],"sourcesContent":["import type { UserConfig } from 'kubb'\nimport type { TransformParams } from './transform.ts'\n\n/**\n * Wraps a transform so a repeated request for the same file, content and config returns the\n * previous result. TypeScript asks again for specs it already transformed (another project, a\n * reload), and a Kubb build of a large spec takes seconds. A failed transform is not kept.\n */\nexport function cacheTransform<TResult>(\n transform: (params: TransformParams, config?: UserConfig) => Promise<TResult>,\n): (params: TransformParams, config?: UserConfig) => Promise<TResult> {\n const results = new Map<string, { content: string; config?: UserConfig; result: Promise<TResult> }>()\n\n return (params, config) => {\n const cached = results.get(params.fileName)\n // A reloaded config is a new object, so comparing by reference catches every config change.\n if (cached && cached.content === params.content && cached.config === config) return cached.result\n\n const result = transform(params, config)\n results.set(params.fileName, { content: params.content, config, result })\n result.catch(() => results.delete(params.fileName))\n return result\n }\n}\n","import { createHash } from 'node:crypto'\nimport { readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { UserConfig } from 'kubb'\nimport { configFileCandidates, findConfigFile, loadConfigFile } from 'unplugin-kubb'\n\n/**\n * A Kubb config found for a TypeScript project, with what TypeScript needs to reload it.\n */\nexport type ProjectConfig = {\n /**\n * The project folder.\n */\n dir: string\n /**\n * The configs the file exports, empty when there is no config file.\n */\n configs: Array<UserConfig>\n /**\n * The config file, plus every file the CLI would pick up in `dir`, so adding one reloads too.\n */\n watchedFiles: Array<string>\n /**\n * Changes when the config file changes, so TypeScript transforms its specs again.\n */\n identity: string\n /**\n * Why the config file failed to load. Each transform reports it on the spec.\n */\n error?: string\n}\n\n/**\n * Finds the Kubb config the way the Kubb CLI does, from `dir` up, and loads it. A config that\n * exports a function is called with no CLI options.\n */\nexport async function loadProjectConfig(dir: string): Promise<ProjectConfig> {\n dir = resolve(dir)\n const file = findConfigFile(dir)\n const watchedFiles = [...new Set([...(file ? [file] : []), ...configFileCandidates(dir)])]\n if (!file) return { dir, configs: [], watchedFiles, identity: 'none' }\n\n const identity = createHash('sha256').update(readFileSync(file)).digest('hex')\n try {\n return { dir, configs: await loadConfigFile<UserConfig>({ file, cli: {} }), watchedFiles, identity }\n } catch (error) {\n return { dir, configs: [], watchedFiles, identity, error: `${file} failed to load: ${error instanceof Error ? error.message : String(error)}` }\n }\n}\n","/**\n * A JSON-RPC 2.0 message as the TypeScript content mapper host sends and expects it.\n */\nexport type Message = {\n id?: number | string\n method?: string\n params?: unknown\n result?: unknown\n error?: { code: number; message: string }\n}\n\nconst separator = '\\r\\n\\r\\n'\n\n/**\n * Frames a message with the LSP base protocol `Content-Length` header the host reads.\n */\nexport function encode(message: Message): Buffer {\n const body = Buffer.from(JSON.stringify({ jsonrpc: '2.0', ...message }))\n\n return Buffer.concat([Buffer.from(`Content-Length: ${body.length}${separator}`), body])\n}\n\n/**\n * Returns a stream handler that collects `Content-Length` framed chunks and calls `onMessage`\n * once per complete message, however the chunks split the frames.\n */\nexport function createDecoder(onMessage: (message: Message) => void): (chunk: Buffer) => void {\n let buffer = Buffer.alloc(0)\n\n return (chunk) => {\n buffer = Buffer.concat([buffer, chunk])\n\n while (true) {\n const headerEnd = buffer.indexOf(separator)\n if (headerEnd === -1) return\n\n const header = buffer.subarray(0, headerEnd).toString()\n const length = Number(/content-length:\\s*(\\d+)/i.exec(header)?.[1])\n if (!Number.isInteger(length)) throw new Error(`Missing Content-Length header in \"${header}\"`)\n\n const start = headerEnd + separator.length\n if (buffer.length < start + length) return\n\n const body = buffer.subarray(start, start + length).toString()\n buffer = buffer.subarray(start + length)\n onMessage(JSON.parse(body) as Message)\n }\n }\n}\n","import * as yaml from 'yaml'\n\n/**\n * A range in the spec text, as `[start, end)` offsets.\n */\nexport type Range = { start: number; end: number }\n\nconst toRange = ([start, end]: yaml.Range): Range => ({ start, end })\n\nconst unescapeToken = (token: string) => token.replaceAll('~1', '/').replaceAll('~0', '~')\n\n/**\n * Walks a JSON pointer through maps and sequences; the range is the last key or item it reached,\n * or with `value` the scalar value of that key.\n */\nfunction findPointer(document: yaml.Document, pointer: string, value = false): Range | undefined {\n const tokens = pointer.replace(/^#/, '').split('/').slice(1).map(unescapeToken)\n const reached = tokens.reduce<{ node: unknown; range: Range | undefined } | undefined>(\n (at, token) => {\n if (yaml.isMap(at?.node)) {\n const pair = at.node.items.find((item) => yaml.isScalar(item.key) && String(item.key.value) === token)\n return pair && yaml.isScalar(pair.key) && pair.key.range ? { node: pair.value, range: toRange(pair.key.range) } : undefined\n }\n if (yaml.isSeq(at?.node)) {\n const item = at.node.items[Number(token)]\n return yaml.isNode(item) && item.range ? { node: item, range: toRange(item.range) } : undefined\n }\n return undefined\n },\n { node: document.contents, range: undefined },\n )\n if (!value) return reached?.range\n return yaml.isScalar(reached?.node) && reached.node.range ? toRange(reached.node.range) : undefined\n}\n\n/**\n * The first `$ref` whose value is `ref`.\n */\nfunction findRefUsage(document: yaml.Document, ref: string): Range | undefined {\n let found: Range | undefined\n yaml.visit(document, {\n Pair(_, { key, value }) {\n if (!yaml.isScalar(key) || key.value !== '$ref' || !yaml.isScalar(value) || value.value !== ref || !value.range) return\n found = toRange(value.range)\n return yaml.visit.BREAK\n },\n })\n return found\n}\n\n/**\n * Maps JSON pointers to ranges in an already parsed spec, the same way `@kubb/adapter-oas`'s\n * `locate` does from the spec text. Reusing the document the build parsed saves a second parse of\n * the spec on every transform. An unresolved `$ref` falls back to its first usage.\n */\nexport function createLocator(document: yaml.Document): (location: { pointer: string; ref?: string; value?: boolean }) => Range | undefined {\n return ({ pointer, ref, value }) => findPointer(document, pointer, value) ?? (ref ? findRefUsage(document, ref) : undefined)\n}\n","import ts from '@typescript/typescript6'\n\n/**\n * A span map segment in the tuple form TypeScript reads:\n * `[virtualStart, virtualLength, originalStart, originalLength, kind, features]`.\n */\nexport type Segment = [number, number, number, number, number, number]\n\n/**\n * What the build saw, keyed by the names `@kubb/plugin-ts` emitted.\n */\nexport type Targets = {\n /**\n * Emitted type name to the `components.schemas` key it came from.\n */\n schemas: Map<string, string>\n /**\n * Emitted operation name prefix (such as `GetPetById`) to its path and method.\n */\n operations: Map<string, { path: string; method: string }>\n}\n\ntype Locate = (pointer: string) => { start: number; end: number } | undefined\n\n/**\n * Finds a spec key (`locate`) or the scalar value of a key (`locateValue`) from a JSON pointer.\n */\ntype Locators = { locate: Locate; locateValue: Locate }\n\nconst kindVerbatim = 0\nconst kindAlias = 2\n// Hover, Definition, TypeDefinition, Implementation, References, DocumentHighlights.\nconst features = 1 | 8 | 16 | 32 | 64 | 128\n// Only schema names rename into the spec. A stale `$ref` shows as an error, but a stale `required` entry fails silently.\nconst renameFeature = 256\n\nconst refPrefix = '#/components/schemas/'\n\nconst escapeToken = (token: string) => token.replaceAll('~', '~0').replaceAll('/', '~1')\n\n/**\n * Narrows an operation type to the part of the operation it was generated from, by the suffix\n * `@kubb/plugin-ts` appends to the operation name.\n */\nfunction operationPointer(base: string, suffix: string): string {\n const status = /^Status(\\d{3}|Default)/.exec(suffix)?.[1]\n if (status) return `${base}/responses/${status === 'Default' ? 'default' : status}`\n if (/^(Path|Query|Header)/.test(suffix)) return `${base}/parameters`\n if (/^(Body|Request|MutationRequest)/.test(suffix)) return `${base}/requestBody`\n return base\n}\n\nconst longestPrefix = (keys: Iterable<string>, name: string) => [...keys].filter((key) => name.startsWith(key)).sort((a, b) => b.length - a.length)[0]\n\n/**\n * Pointers to try for one declaration, most specific first. Enums extracted from a schema property\n * (`OrderStatusEnumKey`, `orderStatusEnum`) point at that property, then at the schema.\n */\nfunction declarationPointers(name: string, { schemas, operations }: Targets): Array<string> {\n const schema = schemas.get(name)\n if (schema) return [`#/components/schemas/${escapeToken(schema)}`]\n\n const schemaPrefix = longestPrefix(schemas.keys(), name)\n const operationPrefix = longestPrefix(operations.keys(), name)\n\n if (schemaPrefix !== undefined && (operationPrefix === undefined || schemaPrefix.length > operationPrefix.length)) {\n const base = `#/components/schemas/${escapeToken(schemas.get(schemaPrefix)!)}`\n const property = name.slice(schemaPrefix.length).replace(/(Enum)?Key$|Enum$/, '')\n return property ? [`${base}/properties/${escapeToken(property[0]!.toLowerCase() + property.slice(1))}`, base] : [base]\n }\n if (operationPrefix === undefined) return []\n\n const { path, method } = operations.get(operationPrefix)!\n return [operationPointer(`#/paths/${escapeToken(path)}/${method.toLowerCase()}`, name.slice(operationPrefix.length))]\n}\n\n/**\n * A property type without `| null` and one level of `T[]` or `Array<T>`, which the spec writes under `items`.\n */\nfunction unwrap(type: ts.TypeNode | undefined): { type: ts.TypeNode; items: boolean } | undefined {\n const members =\n type && ts.isUnionTypeNode(type)\n ? type.types.filter((member) => !(ts.isLiteralTypeNode(member) && member.literal.kind === ts.SyntaxKind.NullKeyword))\n : [type]\n const [single] = members.length === 1 ? members : []\n if (!single) return undefined\n if (ts.isArrayTypeNode(single)) return { type: single.elementType, items: true }\n if (ts.isTypeReferenceNode(single) && single.typeName.getText() === 'Array' && single.typeArguments?.length === 1)\n return { type: single.typeArguments[0]!, items: true }\n return { type: single, items: false }\n}\n\n/**\n * The members of an interface, or of a type alias for an object literal.\n */\nfunction typeMembers(statement: ts.TypeAliasDeclaration | ts.InterfaceDeclaration): ts.NodeArray<ts.TypeElement> | undefined {\n if (ts.isInterfaceDeclaration(statement)) return statement.members\n return ts.isTypeLiteralNode(statement.type) ? statement.type.members : undefined\n}\n\n/**\n * Links generated names to the spec keys they came from: schemas and their (nested) properties,\n * and operation types to the operation, parameters, request body or response. A schema type named\n * exactly like its key is verbatim, so a rename in TypeScript renames the key. A reference to a\n * schema type maps to the end of the `$ref` that points at that schema, so the rename updates it too.\n */\nexport function createMappings(text: string, content: string, { locate, locateValue }: Locators, targets: Targets): Array<Segment> {\n const sourceFile = ts.createSourceFile('index.ts', text, ts.ScriptTarget.Latest, true)\n const segments: Array<Segment> = []\n\n const add = (name: ts.Node, rename: boolean, ...pointers: Array<string>) => {\n const range = pointers.map(locate).find(Boolean)\n if (!range) return\n const verbatim = rename && content.slice(range.start, range.end) === name.getText(sourceFile)\n segments.push([\n name.getStart(sourceFile),\n name.getWidth(sourceFile),\n range.start,\n range.end - range.start,\n verbatim ? kindVerbatim : kindAlias,\n verbatim ? features | renameFeature : features,\n ])\n }\n\n // Only a reference whose `$ref` ends in the same text renames; anything else would break the spec.\n const addRef = (inner: ReturnType<typeof unwrap>, pointer: string) => {\n if (!inner || !ts.isTypeReferenceNode(inner.type) || !ts.isIdentifier(inner.type.typeName)) return\n const reference = inner.type.typeName\n const name = reference.text\n if (!targets.schemas.has(name)) return\n const range = locateValue(`${pointer}${inner.items ? '/items' : ''}/$ref`)\n if (!range) return\n // The `$ref` value may be quoted, so count the name back from the end of its text.\n const start = range.start + content.slice(range.start, range.end).replace(/['\"]$/, '').length - name.length\n if (content.slice(start - refPrefix.length, start + name.length) !== refPrefix + name) return\n segments.push([reference.getStart(sourceFile), reference.getWidth(sourceFile), start, name.length, kindVerbatim, features | renameFeature])\n }\n\n const addMembers = (members: ts.NodeArray<ts.TypeElement>, pointer: string) => {\n for (const member of members) {\n if (!ts.isPropertySignature(member) || !(ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))) continue\n const propertyPointer = `${pointer}/properties/${escapeToken(member.name.text)}`\n add(member.name, false, propertyPointer)\n const inner = unwrap(member.type)\n addRef(inner, propertyPointer)\n if (inner && ts.isTypeLiteralNode(inner.type)) addMembers(inner.type.members, inner.items ? `${propertyPointer}/items` : propertyPointer)\n }\n }\n\n for (const statement of sourceFile.statements) {\n if (ts.isVariableStatement(statement)) {\n // Enum objects (`export const orderStatusEnum = { ... } as const`) match like their `Key` type.\n for (const declaration of statement.declarationList.declarations) {\n if (!ts.isIdentifier(declaration.name)) continue\n const name = declaration.name.text\n add(declaration.name, false, ...declarationPointers(name, targets), ...declarationPointers(name[0]!.toUpperCase() + name.slice(1), targets))\n }\n continue\n }\n if (!ts.isTypeAliasDeclaration(statement) && !ts.isInterfaceDeclaration(statement)) continue\n const pointers = declarationPointers(statement.name.text, targets)\n const isSchema = targets.schemas.has(statement.name.text)\n add(statement.name, isSchema, ...pointers)\n\n // Property names only resolve under a schema, not under operation parameters or responses.\n const pointer = pointers[0]\n if (!pointer || !isSchema) continue\n const members = typeMembers(statement)\n if (members) addMembers(members, pointer)\n else if (ts.isTypeAliasDeclaration(statement)) addRef(unwrap(statement.type), pointer)\n }\n\n return segments\n}\n","import { dirname } from 'node:path'\nimport ts from '@typescript/typescript6'\nimport type { UserConfig } from 'kubb'\nimport { Hookable, type KubbHooks } from 'kubb/kit'\nimport { pluginTs, pluginTsName, resolverTs } from '@kubb/plugin-ts'\nimport { generateModule } from 'unplugin-kubb'\nimport { parseDocument } from 'yaml'\nimport { createLocator } from './locate.ts'\nimport { createMappings, type Segment, type Targets } from './mappings.ts'\n\n/**\n * Parameters of the content mapper `transform` request.\n */\nexport type TransformParams = {\n fileName: string\n content: string\n}\n\n/**\n * The module TypeScript checks in place of the spec, and the segments linking it to the spec.\n */\nexport type TransformResult = {\n text: string\n extension: '.ts'\n mappings?: Array<Segment>\n diagnostics?: Array<{ messageText: string; start: number; length: number }>\n}\n\nconst scanner = ts.createScanner(ts.ScriptTarget.Latest, true)\n\n// A keyword such as `string` or `class` scans as a keyword, not an identifier, so it is not kept.\nfunction isPlainIdentifier(name: string): boolean {\n scanner.setText(name)\n return scanner.scan() === ts.SyntaxKind.Identifier && scanner.getTokenEnd() === name.length\n}\n\n/**\n * Keeps a name that is already a valid type name as the spec wrote it (`pet`, `PET_STATUS`), so a\n * schema type matches its key and renames it. Composed names such as `getPetById Status 200` and\n * keys that are not identifiers keep the `@kubb/plugin-ts` PascalCase.\n */\nconst specName = (name: string) => (isPlainIdentifier(name) ? name : resolverTs.name(name))\n\n/**\n * Lets `@kubb/plugin-ts` name schema types after their spec keys, unless the config sets its own `resolver.name`.\n */\nfunction keepSpecCasing(config: UserConfig): UserConfig {\n return {\n ...config,\n plugins: config.plugins?.map((plugin) =>\n plugin.name === pluginTsName\n ? { ...plugin, options: { ...plugin.options, resolver: { name: specName, ...(plugin.options as { resolver?: object })?.resolver } } }\n : plugin,\n ),\n }\n}\n\n/**\n * Generates the module for one spec with `generateModule` from `unplugin-kubb`, the same one a\n * bundler loads. Without a config, only `@kubb/plugin-ts` runs. The spec text comes from the\n * request, so unsaved edits are checked too. It is parsed once and shared by the build, the\n * diagnostics and the mappings.\n */\nexport async function transform({ fileName, content }: TransformParams, config?: UserConfig): Promise<TransformResult> {\n const document = parseDocument(content)\n if (document.errors.length) {\n return {\n text: 'export {}',\n extension: '.ts',\n diagnostics: document.errors.map((error) => ({ messageText: error.message, start: error.pos[0], length: error.pos[1] - error.pos[0] })),\n }\n }\n\n const hooks = new Hookable<KubbHooks>()\n const targets: Targets = { schemas: new Map(), operations: new Map() }\n hooks.hook('kubb:generate:schema', (node, { resolver }) => {\n if (node.name) targets.schemas.set(resolver.name(node.name), node.name)\n })\n hooks.hook('kubb:generate:operation', (node, { resolver }) => {\n if (!('path' in node && node.path && node.method)) return\n // Operation types are always PascalCase, whatever casing a schema type keeps.\n const target = { path: node.path, method: node.method }\n targets.operations.set(resolver.name(node.operationId), target).set(resolverTs.name(node.operationId), target)\n })\n\n const { text, errors } = await generateModule({\n root: dirname(fileName),\n input: document.toJS(),\n config: keepSpecCasing(config ?? { output: { path: '.' }, plugins: [pluginTs()] }),\n hooks,\n })\n\n const locate = createLocator(document)\n\n if (errors.length) {\n return {\n text: 'export {}',\n extension: '.ts',\n diagnostics: errors.map((error) => {\n const range = error.location && 'pointer' in error.location ? locate(error.location) : undefined\n return { messageText: error.message, start: range?.start ?? 0, length: range ? range.end - range.start : 0 }\n }),\n }\n }\n\n if (config && !text) {\n return {\n text: 'export {}',\n extension: '.ts',\n diagnostics: [{ messageText: 'kubb.config.ts generated no code for this spec. Add a plugin such as pluginTs().', start: 0, length: 0 }],\n }\n }\n\n return {\n text,\n extension: '.ts',\n mappings: createMappings(text, content, { locate: (pointer) => locate({ pointer }), locateValue: (pointer) => locate({ pointer, value: true }) }, targets),\n }\n}\n","import { dirname } from 'node:path'\nimport { selectConfig } from 'unplugin-kubb'\nimport { cacheTransform } from './cache.ts'\nimport { loadProjectConfig, type ProjectConfig } from './config.ts'\nimport { createDecoder, encode, type Message } from './rpc.ts'\nimport { transform, type TransformParams } from './transform.ts'\n\n// stdout carries the protocol, so every other stdout write (any console method, direct writes from\n// Kubb or its plugins) goes to stderr.\nconst writeProtocol = process.stdout.write.bind(process.stdout)\nprocess.stdout.write = process.stderr.write.bind(process.stderr) as typeof process.stdout.write\n\n// The load promise is stored right away, so a transform sent before the load finishes waits for it.\nconst projects = new Map<string, Promise<ProjectConfig>>()\n\nconst cachedTransform = cacheTransform(transform)\n\nconst handlers: Record<string, (params: never) => unknown> = {\n initialize: () => ({ protocolVersion: 1, positionEncoding: 'utf-16', diagnosticSource: 'kubb' }),\n // `dynamicConfig` in package.json: TypeScript watches `watchedFiles` and opens the project again\n // when one changes, then transforms its specs again when `configIdentity` differs.\n openProject: async ({ projectHandle, configFileName, options }: { projectHandle: string; configFileName?: string; options?: unknown }) => {\n const loading = loadProjectConfig(configFileName ? dirname(configFileName) : process.cwd())\n projects.set(projectHandle, loading)\n const project = await loading\n\n return {\n configIdentity: project.identity,\n watchedFiles: project.watchedFiles,\n ...(options != null && { optionDiagnostics: [{ path: [], messageText: 'openapi-import has no options. Set plugin options in kubb.config.ts.' }] }),\n }\n },\n closeProject: ({ projectHandle }: { projectHandle: string }) => {\n projects.delete(projectHandle)\n return null\n },\n transform: async (params: TransformParams & { projectHandle: string }) => {\n const project = await projects.get(params.projectHandle)\n if (project?.error) return { text: 'export {}', extension: '.ts', diagnostics: [{ messageText: project.error, start: 0, length: 0 }] }\n\n return cachedTransform(params, project && selectConfig({ configs: project.configs, fileName: params.fileName, cwd: project.dir }))\n },\n}\n\nasync function handle({ id, method = '', params }: Message): Promise<void> {\n const handler = handlers[method]\n if (id === undefined) return\n\n try {\n if (!handler) {\n writeProtocol(encode({ id, error: { code: -32601, message: `Unknown method \"${method}\"` } }))\n return\n }\n const result = await handler(params as never)\n writeProtocol(encode({ id, result: result ?? null }))\n } catch (error) {\n writeProtocol(encode({ id, error: { code: -32603, message: error instanceof Error ? (error.stack ?? error.message) : String(error) } }))\n }\n}\n\nprocess.stdin.on(\n 'data',\n createDecoder((message) => void handle(message)),\n)\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openapi-import",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Import OpenAPI specs in TypeScript with types from Kubb, through TypeScript 7.1 content mappers. No generated files.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"code-generation",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@kubb/plugin-ts": "^5.0.14",
|
|
53
53
|
"@typescript/typescript6": "^6.0.2",
|
|
54
|
-
"unplugin-kubb": "^5.12.
|
|
54
|
+
"unplugin-kubb": "^5.12.7",
|
|
55
55
|
"yaml": "^2.9.1"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"@kubb/plugin-zod": "^5.4.12",
|
|
61
61
|
"@types/node": "22.20.2",
|
|
62
62
|
"@vitest/coverage-v8": "^5.0.5",
|
|
63
|
-
"kubb": "^5.12.
|
|
63
|
+
"kubb": "^5.12.7",
|
|
64
64
|
"oxfmt": "^0.72.0",
|
|
65
65
|
"oxlint": "^1.88.0",
|
|
66
66
|
"tsdown": "^0.23.1",
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"vitest": "^5.0.5"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"kubb": "^5.12.
|
|
71
|
+
"kubb": "^5.12.7"
|
|
72
72
|
},
|
|
73
73
|
"typescript": {
|
|
74
74
|
"contentMapper": {
|