openapi-import 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,27 +1,37 @@
1
1
  # openapi-import
2
2
 
3
- Import an OpenAPI spec straight into TypeScript and get the types Kubb generates, with no generated files on disk.
3
+ Import an OpenAPI spec in TypeScript and get the code the plugins in your `kubb.config.ts` generate, without generated files.
4
4
 
5
5
  ```ts
6
- import type { Pet } from './petStore.openapi.yaml'
7
-
8
- const pet: Pet = { name: 'Rex', photoUrls: [] }
6
+ import { type Pet, petSchema } from './petStore.openapi.yaml'
9
7
  ```
10
8
 
11
- It is a [TypeScript content mapper](https://github.com/microsoft/typescript-go/pull/4712). TypeScript 7.1 calls it for each spec file and type-checks the `@kubb/plugin-ts` output in its place.
9
+ It is a [TypeScript content mapper](https://github.com/microsoft/typescript-go/pull/4712): TypeScript 7.1 type-checks the output of every plugin in your config in place of the spec.
12
10
 
13
11
  > [!WARNING]
14
- > Experimental. Content mappers need a TypeScript 7.1 build that supports `--runExternalCode` (`typescript@next` today). Imports are type-only: content-mapped files are not emitted to JavaScript, so values such as enum objects do not exist at run time.
12
+ > Experimental. It needs TypeScript 7.1.0-beta or later with `--runExternalCode`. TypeScript does not emit the spec to JavaScript, so values such as `petSchema` only exist at run time when a bundler loads the spec with [`unplugin-kubb`](https://github.com/kubb-labs/kubb/tree/main/packages/unplugin-kubb).
13
+
14
+ ## Features
15
+
16
+ - Import a `.openapi.yaml` spec straight into TypeScript, with no generated files.
17
+ - Works without a config: you get the types from `@kubb/plugin-ts`.
18
+ - Add a `kubb.config.ts` to get Zod schemas, clients and the output of any other Kubb plugin from the same import.
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 and its `$ref`s in the spec are 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.
15
25
 
16
26
  ## Setup
17
27
 
18
28
  ```bash
19
- pnpm add -D kubb openapi-import typescript@next
29
+ pnpm add -D kubb openapi-import typescript@beta @kubb/plugin-ts
20
30
  ```
21
31
 
22
- npm rejects `typescript@next` against the `typescript@^7.0.2` peer range of `@kubb/plugin-ts`, so add `--legacy-peer-deps` there.
32
+ With npm, `tsc` runs TypeScript 6, because `@typescript/typescript6` links its `tsc` over the one from `typescript`. Run `node node_modules/typescript/bin/tsc` instead.
23
33
 
24
- Name your specs with an `.openapi.yaml` extension, such as `petStore.openapi.yaml`, and register that extension in `tsconfig.json`:
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.
25
35
 
26
36
  ```json
27
37
  {
@@ -29,19 +39,60 @@ Name your specs with an `.openapi.yaml` extension, such as `petStore.openapi.yam
29
39
  }
30
40
  ```
31
41
 
32
- TypeScript sends every file with a registered extension that `include` matches to the mapper, not only the files you import. A plain `.yaml` would also pick up files such as `docker-compose.yaml` and fail on them, and it would block other content mappers from `.yaml`. JSON specs cannot be mapped: TypeScript treats any extension ending in `.json` as built-in.
42
+ Add the plugins you want to `kubb.config.ts`, and install them, such as `@kubb/plugin-zod` and `zod`:
43
+
44
+ ```ts
45
+ import { pluginTs } from '@kubb/plugin-ts'
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
+ })
53
+ ```
54
+
55
+ The mapper finds the config like the Kubb CLI does and reloads it when it changes. With several configs, a spec uses the one whose `input` matches it. Without a config, only `@kubb/plugin-ts` runs.
33
56
 
34
- Run the type check with external code allowed:
57
+ Run the type check:
35
58
 
36
59
  ```bash
37
60
  tsc --noEmit --runExternalCode
38
61
  ```
39
62
 
40
- VS Code passes `--runExternalCode` to the TypeScript language server only in trusted workspaces.
63
+ VS Code only passes `--runExternalCode` in trusted workspaces.
64
+
65
+ ## Run time
66
+
67
+ `tsc` only checks the types, so values such as `petSchema` need a bundler. Add `kubb()` from `kubb/vite`, or another entry such as `kubb/webpack` or `kubb/rollup`, without a `config` option. It then reads the same `kubb.config.ts` as `tsc`:
68
+
69
+ ```ts
70
+ // vite.config.ts
71
+ import kubb from 'kubb/vite'
72
+ import { defineConfig } from 'vite'
73
+
74
+ export default defineConfig({
75
+ plugins: [kubb()],
76
+ })
77
+ ```
78
+
79
+ The types and the values come from the same import:
80
+
81
+ ```ts
82
+ import { type GetPetByIdPath, type GetPetByIdResponse, petSchema } from '../petStore.openapi.yaml'
83
+
84
+ export async function getPetById({ petId }: GetPetByIdPath): Promise<GetPetByIdResponse> {
85
+ const response = await fetch(`https://petstore3.swagger.io/api/v3/pet/${petId}`)
86
+
87
+ return petSchema.parse(await response.json())
88
+ }
89
+ ```
90
+
91
+ A config with an `input` also writes the generated files at build time, so leave it out to import specs only. The bundler reads `kubb.config.ts` once, so restart it after you change the config.
41
92
 
42
93
  ## Editor support
43
94
 
44
- Generated names link back to the keys they came from in the spec. Go to definition and find references cross from TypeScript into the YAML, and hovering a key in the YAML shows its generated type.
95
+ Go to definition, find references and hover link generated names to their keys in the spec. Schema types are named like their keys. Renaming one renames the key and the `$ref`s that point at it, when they sit on a property, an array item or a schema alias. Other `$ref`s, such as inside `allOf` or a response, are not renamed.
45
96
 
46
97
  | Generated name | Jumps to |
47
98
  | ------------------------------------------------------------- | ------------------------------------------------------------------------- |
@@ -53,35 +104,14 @@ Generated names link back to the keys they came from in the spec. Go to definiti
53
104
  | `GetPetByIdStatus404` | `responses.404` |
54
105
  | `AddPetBody` | the operation's `requestBody` |
55
106
 
56
- Spec errors, such as an unresolved `$ref`, show on the key or value they point at.
57
-
58
- ## Options
59
-
60
- Set options on the `contentMappers` entry. TypeScript reports an unknown key or an invalid value on `tsconfig.json`.
61
-
62
- ```json
63
- {
64
- "contentMappers": [
65
- {
66
- "package": "openapi-import",
67
- "extensions": [".openapi.yaml"],
68
- "options": { "arrayType": "generic" }
69
- }
70
- ]
71
- }
72
- ```
73
-
74
- | Option | Values | Default | Description |
75
- | ----------- | ---------------------- | --------- | ------------------------------------------------------------------------ |
76
- | `arrayType` | `'array'`, `'generic'` | `'array'` | Prints arrays as `T[]` or `Array<T>`, like the `@kubb/plugin-ts` option. |
77
-
78
- See [`examples/pet-store`](./examples/pet-store) for a working setup.
107
+ Spec errors, such as an unresolved `$ref`, show on the key they point at. See [`examples/pet-store`](./examples/pet-store) for a working setup.
79
108
 
80
109
  ## Limits
81
110
 
82
- - Only `@kubb/plugin-ts` runs, and `arrayType` is its only option you can set. `kubb.config.ts` is not read.
83
- - Properties of operation types (path parameters, inline response bodies) do not link to the spec, and renaming a type does not rename the key in the spec.
84
- - A changed spec runs a full Kubb build: about 0.4 s and 155 MB for a 10 KB spec, about 2.6 s and 245 MB for a 1.4 MB spec. A repeated request for unchanged content reuses the last result.
111
+ - Code a plugin writes to a separate file, such as a bundled client runtime, is not included. Point imports like the client's `importPath` at a package.
112
+ - Properties of operation types don't link to the spec, and renaming a property doesn't rename its key.
113
+ - Files that `kubb.config.ts` imports are not watched. Restart the TypeScript server after you change them.
114
+ - A changed spec runs a full Kubb build: about 0.4 s for a 10 KB spec and 2.6 s for a 1.4 MB spec.
85
115
 
86
116
  ## Supporting Kubb
87
117
 
package/dist/server.js CHANGED
@@ -1,26 +1,27 @@
1
- import { dirname } from "node:path";
2
- import { adapterOas } from "@kubb/adapter-oas";
3
- import { Diagnostics, createKubb, memoryStorage } from "@kubb/core";
4
- import { parserTs } from "@kubb/parser-ts";
5
- import { pluginTs } from "@kubb/plugin-ts";
1
+ import { dirname, resolve } from "node:path";
2
+ import { configFileCandidates, findConfigFile, generateModule, loadConfigFile, selectConfig } from "unplugin-kubb";
3
+ import { createHash } from "node:crypto";
4
+ import { readFileSync } from "node:fs";
5
+ import ts from "@typescript/typescript6";
6
+ import { Hookable } from "kubb/kit";
7
+ import { pluginTs, pluginTsName, resolverTs } from "@kubb/plugin-ts";
6
8
  import * as yaml from "yaml";
7
9
  import { parseDocument } from "yaml";
8
- import ts from "@typescript/typescript6";
9
10
  //#region src/cache.ts
10
11
  /**
11
- * Wraps a transform so a repeated request for the same file, content and options returns the
12
+ * Wraps a transform so a repeated request for the same file, content and config returns the
12
13
  * previous result. TypeScript asks again for specs it already transformed (another project, a
13
14
  * reload), and a Kubb build of a large spec takes seconds. A failed transform is not kept.
14
15
  */
15
16
  function cacheTransform(transform) {
16
17
  const results = /* @__PURE__ */ new Map();
17
- return (params, options = {}) => {
18
+ return (params, config) => {
18
19
  const cached = results.get(params.fileName);
19
- if (cached && cached.content === params.content && cached.arrayType === options.arrayType) return cached.result;
20
- const result = transform(params, options);
20
+ if (cached && cached.content === params.content && cached.config === config) return cached.result;
21
+ const result = transform(params, config);
21
22
  results.set(params.fileName, {
22
23
  content: params.content,
23
- arrayType: options.arrayType,
24
+ config,
24
25
  result
25
26
  });
26
27
  result.catch(() => results.delete(params.fileName));
@@ -28,47 +29,38 @@ function cacheTransform(transform) {
28
29
  };
29
30
  }
30
31
  //#endregion
31
- //#region src/options.ts
32
- const arrayTypes = ["array", "generic"];
32
+ //#region src/config.ts
33
33
  /**
34
- * Validates the raw `options` value from `openProject`. Unknown keys and invalid values are
35
- * dropped and reported, so a typo shows up in `tsconfig.json` instead of being silently ignored.
34
+ * Finds the Kubb config the way the Kubb CLI does, from `dir` up, and loads it. A config that
35
+ * exports a function is called with no CLI options.
36
36
  */
37
- function parseOptions(raw) {
38
- const options = {};
39
- const diagnostics = [];
40
- if (raw === void 0 || raw === null) return {
41
- options,
42
- diagnostics
37
+ async function loadProjectConfig(dir) {
38
+ dir = resolve(dir);
39
+ const file = findConfigFile(dir);
40
+ const watchedFiles = [.../* @__PURE__ */ new Set([...file ? [file] : [], ...configFileCandidates(dir)])];
41
+ if (!file) return {
42
+ dir,
43
+ configs: [],
44
+ watchedFiles,
45
+ identity: "none"
43
46
  };
44
- if (typeof raw !== "object" || Array.isArray(raw)) return {
45
- options,
46
- diagnostics: [{
47
- path: [],
48
- messageText: "Expected `options` to be an object."
49
- }]
50
- };
51
- for (const [key, value] of Object.entries(raw)) {
52
- if (key !== "arrayType") {
53
- diagnostics.push({
54
- path: [key],
55
- messageText: `Unknown option "${key}". Supported: arrayType.`
56
- });
57
- continue;
58
- }
59
- if (typeof value !== "string" || !arrayTypes.includes(value)) {
60
- diagnostics.push({
61
- path: [key],
62
- messageText: `Expected "arrayType" to be one of ${arrayTypes.map((type) => `"${type}"`).join(", ")}.`
63
- });
64
- continue;
65
- }
66
- options.arrayType = value;
47
+ const identity = createHash("sha256").update(readFileSync(file)).digest("hex");
48
+ try {
49
+ return {
50
+ dir,
51
+ configs: await loadConfigFile(file, {}),
52
+ watchedFiles,
53
+ identity
54
+ };
55
+ } catch (error) {
56
+ return {
57
+ dir,
58
+ configs: [],
59
+ watchedFiles,
60
+ identity,
61
+ error: `${file} failed to load: ${error instanceof Error ? error.message : String(error)}`
62
+ };
67
63
  }
68
- return {
69
- options,
70
- diagnostics
71
- };
72
64
  }
73
65
  //#endregion
74
66
  //#region src/rpc.ts
@@ -112,9 +104,12 @@ const toRange = ([start, end]) => ({
112
104
  end
113
105
  });
114
106
  const unescapeToken = (token) => token.replaceAll("~1", "/").replaceAll("~0", "~");
115
- /** Walks a JSON pointer through maps and sequences; the range is the last key or item it reached. */
116
- function findPointer(document, pointer) {
117
- return pointer.replace(/^#/, "").split("/").slice(1).map(unescapeToken).reduce((at, token) => {
107
+ /**
108
+ * Walks a JSON pointer through maps and sequences; the range is the last key or item it reached,
109
+ * or with `value` the scalar value of that key.
110
+ */
111
+ function findPointer(document, pointer, value = false) {
112
+ const reached = pointer.replace(/^#/, "").split("/").slice(1).map(unescapeToken).reduce((at, token) => {
118
113
  if (yaml.isMap(at?.node)) {
119
114
  const pair = at.node.items.find((item) => yaml.isScalar(item.key) && String(item.key.value) === token);
120
115
  return pair && yaml.isScalar(pair.key) && pair.key.range ? {
@@ -132,9 +127,13 @@ function findPointer(document, pointer) {
132
127
  }, {
133
128
  node: document.contents,
134
129
  range: void 0
135
- })?.range;
130
+ });
131
+ if (!value) return reached?.range;
132
+ return yaml.isScalar(reached?.node) && reached.node.range ? toRange(reached.node.range) : void 0;
136
133
  }
137
- /** The first `$ref` whose value is `ref`. */
134
+ /**
135
+ * The first `$ref` whose value is `ref`.
136
+ */
138
137
  function findRefUsage(document, ref) {
139
138
  let found;
140
139
  yaml.visit(document, { Pair(_, { key, value }) {
@@ -150,12 +149,14 @@ function findRefUsage(document, ref) {
150
149
  * the spec on every transform. An unresolved `$ref` falls back to its first usage.
151
150
  */
152
151
  function createLocator(document) {
153
- return ({ pointer, ref }) => findPointer(document, pointer) ?? (ref ? findRefUsage(document, ref) : void 0);
152
+ return ({ pointer, ref, value }) => findPointer(document, pointer, value) ?? (ref ? findRefUsage(document, ref) : void 0);
154
153
  }
155
154
  //#endregion
156
155
  //#region src/mappings.ts
156
+ const kindVerbatim = 0;
157
157
  const kindAlias = 2;
158
158
  const features = 249;
159
+ const refPrefix = "#/components/schemas/";
159
160
  const escapeToken = (token) => token.replaceAll("~", "~0").replaceAll("/", "~1");
160
161
  /**
161
162
  * Narrows an operation type to the part of the operation it was generated from, by the suffix
@@ -187,57 +188,81 @@ function declarationPointers(name, { schemas, operations }) {
187
188
  const { path, method } = operations.get(operationPrefix);
188
189
  return [operationPointer(`#/paths/${escapeToken(path)}/${method.toLowerCase()}`, name.slice(operationPrefix.length))];
189
190
  }
190
- /** The object literal a property type describes, looking through `T[]` and `Array<T>`. */
191
- function objectLiteral(type) {
192
- if (!type) return void 0;
193
- if (ts.isTypeLiteralNode(type)) return {
194
- node: type,
195
- items: false
196
- };
197
- if (ts.isArrayTypeNode(type) && ts.isTypeLiteralNode(type.elementType)) return {
198
- node: type.elementType,
191
+ /**
192
+ * A property type without `| null` and one level of `T[]` or `Array<T>`, which the spec writes under `items`.
193
+ */
194
+ function unwrap(type) {
195
+ const members = type && ts.isUnionTypeNode(type) ? type.types.filter((member) => !(ts.isLiteralTypeNode(member) && member.literal.kind === ts.SyntaxKind.NullKeyword)) : [type];
196
+ const [single] = members.length === 1 ? members : [];
197
+ if (!single) return void 0;
198
+ if (ts.isArrayTypeNode(single)) return {
199
+ type: single.elementType,
199
200
  items: true
200
201
  };
201
- if (ts.isTypeReferenceNode(type) && type.typeName.getText() === "Array" && type.typeArguments?.[0] && ts.isTypeLiteralNode(type.typeArguments[0])) return {
202
- node: type.typeArguments[0],
202
+ if (ts.isTypeReferenceNode(single) && single.typeName.getText() === "Array" && single.typeArguments?.length === 1) return {
203
+ type: single.typeArguments[0],
203
204
  items: true
204
205
  };
206
+ return {
207
+ type: single,
208
+ items: false
209
+ };
205
210
  }
206
- /** The members of an interface, or of a type alias for an object literal. */
211
+ /**
212
+ * The members of an interface, or of a type alias for an object literal.
213
+ */
207
214
  function typeMembers(statement) {
208
215
  if (ts.isInterfaceDeclaration(statement)) return statement.members;
209
216
  return ts.isTypeLiteralNode(statement.type) ? statement.type.members : void 0;
210
217
  }
211
218
  /**
212
- * Builds span map segments that link generated declaration and property names to the keys they
213
- * came from in the spec, so go to definition, hover and find references cross between the two.
214
- *
215
- * Declarations of component schemas map to `components.schemas.<name>`, their properties to
216
- * `properties.<name>` (nested object literals and arrays of them included), and operation types to
217
- * the operation, its parameters, request body or response. A name `locate` cannot place is left
218
- * synthesized.
219
+ * Links generated names to the spec keys they came from: schemas and their (nested) properties,
220
+ * and operation types to the operation, parameters, request body or response. A schema type named
221
+ * exactly like its key is verbatim, so a rename in TypeScript renames the key. A reference to a
222
+ * schema type maps to the end of the `$ref` that points at that schema, so the rename updates it too.
219
223
  */
220
- function createMappings(text, locate, targets) {
224
+ function createMappings(text, content, { locate, locateValue }, targets) {
221
225
  const sourceFile = ts.createSourceFile("index.ts", text, ts.ScriptTarget.Latest, true);
222
226
  const segments = [];
223
- const add = (name, ...pointers) => {
227
+ const add = (name, rename, ...pointers) => {
224
228
  const range = pointers.map(locate).find(Boolean);
225
- if (range) segments.push([
229
+ if (!range) return;
230
+ const verbatim = rename && content.slice(range.start, range.end) === name.getText(sourceFile);
231
+ segments.push([
226
232
  name.getStart(sourceFile),
227
233
  name.getWidth(sourceFile),
228
234
  range.start,
229
235
  range.end - range.start,
230
- kindAlias,
231
- features
236
+ verbatim ? kindVerbatim : kindAlias,
237
+ verbatim ? 505 : features
238
+ ]);
239
+ };
240
+ const addRef = (inner, pointer) => {
241
+ if (!inner || !ts.isTypeReferenceNode(inner.type) || !ts.isIdentifier(inner.type.typeName)) return;
242
+ const reference = inner.type.typeName;
243
+ const name = reference.text;
244
+ if (!targets.schemas.has(name)) return;
245
+ const range = locateValue(`${pointer}${inner.items ? "/items" : ""}/$ref`);
246
+ if (!range) return;
247
+ const start = range.start + content.slice(range.start, range.end).replace(/['"]$/, "").length - name.length;
248
+ if (content.slice(start - 21, start + name.length) !== refPrefix + name) return;
249
+ segments.push([
250
+ reference.getStart(sourceFile),
251
+ reference.getWidth(sourceFile),
252
+ start,
253
+ name.length,
254
+ kindVerbatim,
255
+ 505
232
256
  ]);
233
257
  };
234
258
  const addMembers = (members, pointer) => {
235
259
  for (const member of members) {
236
260
  if (!ts.isPropertySignature(member) || !(ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))) continue;
237
261
  const propertyPointer = `${pointer}/properties/${escapeToken(member.name.text)}`;
238
- add(member.name, propertyPointer);
239
- const literal = objectLiteral(member.type);
240
- if (literal) addMembers(literal.node.members, literal.items ? `${propertyPointer}/items` : propertyPointer);
262
+ add(member.name, false, propertyPointer);
263
+ const inner = unwrap(member.type);
264
+ addRef(inner, propertyPointer);
265
+ if (inner && ts.isTypeLiteralNode(inner.type)) addMembers(inner.type.members, inner.items ? `${propertyPointer}/items` : propertyPointer);
241
266
  }
242
267
  };
243
268
  for (const statement of sourceFile.statements) {
@@ -245,31 +270,60 @@ function createMappings(text, locate, targets) {
245
270
  for (const declaration of statement.declarationList.declarations) {
246
271
  if (!ts.isIdentifier(declaration.name)) continue;
247
272
  const name = declaration.name.text;
248
- add(declaration.name, ...declarationPointers(name[0].toUpperCase() + name.slice(1), targets));
273
+ add(declaration.name, false, ...declarationPointers(name, targets), ...declarationPointers(name[0].toUpperCase() + name.slice(1), targets));
249
274
  }
250
275
  continue;
251
276
  }
252
277
  if (!ts.isTypeAliasDeclaration(statement) && !ts.isInterfaceDeclaration(statement)) continue;
253
278
  const pointers = declarationPointers(statement.name.text, targets);
254
- add(statement.name, ...pointers);
279
+ const isSchema = targets.schemas.has(statement.name.text);
280
+ add(statement.name, isSchema, ...pointers);
255
281
  const pointer = pointers[0];
256
- if (!pointer || !targets.schemas.has(statement.name.text)) continue;
282
+ if (!pointer || !isSchema) continue;
257
283
  const members = typeMembers(statement);
258
284
  if (members) addMembers(members, pointer);
285
+ else if (ts.isTypeAliasDeclaration(statement)) addRef(unwrap(statement.type), pointer);
259
286
  }
260
287
  return segments;
261
288
  }
262
289
  //#endregion
263
290
  //#region src/transform.ts
291
+ const scanner = ts.createScanner(ts.ScriptTarget.Latest, true);
292
+ function isPlainIdentifier(name) {
293
+ scanner.setText(name);
294
+ return scanner.scan() === ts.SyntaxKind.Identifier && scanner.getTokenEnd() === name.length;
295
+ }
296
+ /**
297
+ * Keeps a name that is already a valid type name as the spec wrote it (`pet`, `PET_STATUS`), so a
298
+ * schema type matches its key and renames it. Composed names such as `getPetById Status 200` and
299
+ * keys that are not identifiers keep the `@kubb/plugin-ts` PascalCase.
300
+ */
301
+ const specName = (name) => isPlainIdentifier(name) ? name : resolverTs.name(name);
302
+ /**
303
+ * Lets `@kubb/plugin-ts` name schema types after their spec keys, unless the config sets its own `resolver.name`.
304
+ */
305
+ function keepSpecCasing(config) {
306
+ return {
307
+ ...config,
308
+ plugins: config.plugins?.map((plugin) => plugin.name === pluginTsName ? {
309
+ ...plugin,
310
+ options: {
311
+ ...plugin.options,
312
+ resolver: {
313
+ name: specName,
314
+ ...plugin.options?.resolver
315
+ }
316
+ }
317
+ } : plugin)
318
+ };
319
+ }
264
320
  /**
265
- * Generates the `@kubb/plugin-ts` types for one OpenAPI document as a single module.
266
- *
267
- * The spec text comes from the request, not the disk, so unsaved editor changes are typed too.
268
- * It is parsed once: Kubb builds from the parsed object, and the same document places diagnostics
269
- * and mappings. Nothing is written: the build runs into a memory storage. A failed build returns
270
- * an empty module with the error-level diagnostics placed on the spec key they point at.
321
+ * Generates the module for one spec with `generateModule` from `unplugin-kubb`, the same one a
322
+ * bundler loads. Without a config, only `@kubb/plugin-ts` runs. The spec text comes from the
323
+ * request, so unsaved edits are checked too. It is parsed once and shared by the build, the
324
+ * diagnostics and the mappings.
271
325
  */
272
- async function transform({ fileName, content }, { arrayType } = {}) {
326
+ async function transform({ fileName, content }, config) {
273
327
  const document = parseDocument(content);
274
328
  if (document.errors.length) return {
275
329
  text: "export {}",
@@ -280,42 +334,33 @@ async function transform({ fileName, content }, { arrayType } = {}) {
280
334
  length: error.pos[1] - error.pos[0]
281
335
  }))
282
336
  };
283
- const storage = memoryStorage();
284
- const kubb = createKubb({
285
- root: dirname(fileName),
286
- input: document.toJS(),
287
- output: {
288
- path: ".kubb",
289
- format: false,
290
- lint: false
291
- },
292
- adapter: adapterOas(),
293
- parsers: [parserTs()],
294
- plugins: [pluginTs({
295
- arrayType,
296
- output: { path: "index.ts" }
297
- })],
298
- storage
299
- });
337
+ const hooks = new Hookable();
300
338
  const targets = {
301
339
  schemas: /* @__PURE__ */ new Map(),
302
340
  operations: /* @__PURE__ */ new Map()
303
341
  };
304
- kubb.hooks.hook("kubb:generate:schema", (node, { resolver }) => {
342
+ hooks.hook("kubb:generate:schema", (node, { resolver }) => {
305
343
  if (node.name) targets.schemas.set(resolver.name(node.name), node.name);
306
344
  });
307
- kubb.hooks.hook("kubb:generate:operation", (node, { resolver }) => {
308
- if ("path" in node && node.path && node.method) targets.operations.set(resolver.name(node.operationId), {
345
+ hooks.hook("kubb:generate:operation", (node, { resolver }) => {
346
+ if (!("path" in node && node.path && node.method)) return;
347
+ const target = {
309
348
  path: node.path,
310
349
  method: node.method
311
- });
350
+ };
351
+ targets.operations.set(resolver.name(node.operationId), target).set(resolverTs.name(node.operationId), target);
352
+ });
353
+ const { text, errors } = await generateModule({
354
+ root: dirname(fileName),
355
+ input: document.toJS(),
356
+ config: keepSpecCasing(config ?? {
357
+ output: { path: "." },
358
+ plugins: [pluginTs()]
359
+ }),
360
+ hooks
312
361
  });
313
- const { diagnostics } = await kubb.safeBuild();
314
- const errors = diagnostics.filter(Diagnostics.isProblem).filter((diagnostic) => diagnostic.severity === "error");
315
- const [key] = await storage.readKeys();
316
- const text = key ? await storage.readItem(key) : null;
317
362
  const locate = createLocator(document);
318
- if (errors.length || !text) return {
363
+ if (errors.length) return {
319
364
  text: "export {}",
320
365
  extension: ".ts",
321
366
  diagnostics: errors.map((error) => {
@@ -327,10 +372,25 @@ async function transform({ fileName, content }, { arrayType } = {}) {
327
372
  };
328
373
  })
329
374
  };
375
+ if (config && !text) return {
376
+ text: "export {}",
377
+ extension: ".ts",
378
+ diagnostics: [{
379
+ messageText: "kubb.config.ts generated no code for this spec. Add a plugin such as pluginTs().",
380
+ start: 0,
381
+ length: 0
382
+ }]
383
+ };
330
384
  return {
331
385
  text,
332
386
  extension: ".ts",
333
- mappings: createMappings(text, (pointer) => locate({ pointer }), targets)
387
+ mappings: createMappings(text, content, {
388
+ locate: (pointer) => locate({ pointer }),
389
+ locateValue: (pointer) => locate({
390
+ pointer,
391
+ value: true
392
+ })
393
+ }, targets)
334
394
  };
335
395
  }
336
396
  //#endregion
@@ -345,16 +405,36 @@ const handlers = {
345
405
  positionEncoding: "utf-16",
346
406
  diagnosticSource: "kubb"
347
407
  }),
348
- openProject: ({ projectHandle, options }) => {
349
- const parsed = parseOptions(options);
350
- projects.set(projectHandle, parsed.options);
351
- return parsed.diagnostics.length ? { optionDiagnostics: parsed.diagnostics } : {};
408
+ openProject: async ({ projectHandle, configFileName, options }) => {
409
+ const loading = loadProjectConfig(configFileName ? dirname(configFileName) : process.cwd());
410
+ projects.set(projectHandle, loading);
411
+ const project = await loading;
412
+ return {
413
+ configIdentity: project.identity,
414
+ watchedFiles: project.watchedFiles,
415
+ ...options != null && { optionDiagnostics: [{
416
+ path: [],
417
+ messageText: "openapi-import has no options. Set plugin options in kubb.config.ts."
418
+ }] }
419
+ };
352
420
  },
353
421
  closeProject: ({ projectHandle }) => {
354
422
  projects.delete(projectHandle);
355
423
  return null;
356
424
  },
357
- transform: (params) => cachedTransform(params, projects.get(params.projectHandle))
425
+ transform: async (params) => {
426
+ const project = await projects.get(params.projectHandle);
427
+ if (project?.error) return {
428
+ text: "export {}",
429
+ extension: ".ts",
430
+ diagnostics: [{
431
+ messageText: project.error,
432
+ start: 0,
433
+ length: 0
434
+ }]
435
+ };
436
+ return cachedTransform(params, project && selectConfig(project.configs, params.fileName, project.dir));
437
+ }
358
438
  };
359
439
  async function handle({ id, method = "", params }) {
360
440
  const handler = handlers[method];
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":[],"sources":["../src/cache.ts","../src/options.ts","../src/rpc.ts","../src/locate.ts","../src/mappings.ts","../src/transform.ts","../src/server.ts"],"sourcesContent":["import type { Options } from './options.ts'\nimport type { TransformParams } from './transform.ts'\n\n/**\n * Wraps a transform so a repeated request for the same file, content and options 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, options?: Options) => Promise<TResult>,\n): (params: TransformParams, options?: Options) => Promise<TResult> {\n const results = new Map<string, { content: string; arrayType: Options['arrayType']; result: Promise<TResult> }>()\n\n return (params, options = {}) => {\n const cached = results.get(params.fileName)\n if (cached && cached.content === params.content && cached.arrayType === options.arrayType) return cached.result\n\n const result = transform(params, options)\n results.set(params.fileName, { content: params.content, arrayType: options.arrayType, result })\n result.catch(() => results.delete(params.fileName))\n return result\n }\n}\n","/**\n * Options read from the mapper's `contentMappers[].options` entry in `tsconfig.json`.\n */\nexport type Options = {\n /**\n * Passed to `@kubb/plugin-ts`: `'array'` prints `T[]`, `'generic'` prints `Array<T>`.\n * @default 'array'\n */\n arrayType?: 'array' | 'generic'\n}\n\n/**\n * An invalid option, reported by TypeScript on the `options` object in `tsconfig.json`.\n */\nexport type OptionDiagnostic = {\n path: Array<string>\n messageText: string\n}\n\nconst arrayTypes = ['array', 'generic']\n\n/**\n * Validates the raw `options` value from `openProject`. Unknown keys and invalid values are\n * dropped and reported, so a typo shows up in `tsconfig.json` instead of being silently ignored.\n */\nexport function parseOptions(raw: unknown): { options: Options; diagnostics: Array<OptionDiagnostic> } {\n const options: Options = {}\n const diagnostics: Array<OptionDiagnostic> = []\n\n if (raw === undefined || raw === null) return { options, diagnostics }\n if (typeof raw !== 'object' || Array.isArray(raw)) {\n return { options, diagnostics: [{ path: [], messageText: 'Expected `options` to be an object.' }] }\n }\n\n for (const [key, value] of Object.entries(raw)) {\n if (key !== 'arrayType') {\n diagnostics.push({ path: [key], messageText: `Unknown option \"${key}\". Supported: arrayType.` })\n continue\n }\n if (typeof value !== 'string' || !arrayTypes.includes(value)) {\n diagnostics.push({ path: [key], messageText: `Expected \"arrayType\" to be one of ${arrayTypes.map((type) => `\"${type}\"`).join(', ')}.` })\n continue\n }\n options.arrayType = value as Options['arrayType']\n }\n\n return { options, diagnostics }\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/** Walks a JSON pointer through maps and sequences; the range is the last key or item it reached. */\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/** The first `$ref` whose value is `ref`. */\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 kindAlias = 2\n// Hover, Definition, TypeDefinition, Implementation, References, DocumentHighlights. Rename stays off\n// because only verbatim segments can write edits back to the spec.\nconst features = 1 | 8 | 16 | 32 | 64 | 128\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/** The object literal a property type describes, looking through `T[]` and `Array<T>`. */\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/** The members of an interface, or of a type alias for an object literal. */\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 * Builds span map segments that link generated declaration and property names to the keys they\n * came from in the spec, so go to definition, hover and find references cross between the two.\n *\n * Declarations of component schemas map to `components.schemas.<name>`, their properties to\n * `properties.<name>` (nested object literals and arrays of them included), and operation types to\n * the operation, its parameters, request body or response. A name `locate` cannot place is left\n * synthesized.\n */\nexport function createMappings(text: 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, ...pointers: Array<string>) => {\n const range = pointers.map(locate).find(Boolean)\n if (range) segments.push([name.getStart(sourceFile), name.getWidth(sourceFile), range.start, range.end - range.start, kindAlias, features])\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, 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, ...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 add(statement.name, ...pointers)\n\n // Property names only resolve under a schema, not under operation parameters or responses.\n const pointer = pointers[0]\n if (!pointer || !targets.schemas.has(statement.name.text)) 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 { adapterOas } from '@kubb/adapter-oas'\nimport { createKubb, Diagnostics, memoryStorage } from '@kubb/core'\nimport { parserTs } from '@kubb/parser-ts'\nimport { pluginTs } from '@kubb/plugin-ts'\nimport { parseDocument } from 'yaml'\nimport { createLocator } from './locate.ts'\nimport { createMappings, type Segment, type Targets } from './mappings.ts'\nimport type { Options } from './options.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 * Result of the content mapper `transform` request: the virtual TypeScript module TypeScript\n * checks in place of the spec file, and the segments linking its names back 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 `@kubb/plugin-ts` types for one OpenAPI document as a single module.\n *\n * The spec text comes from the request, not the disk, so unsaved editor changes are typed too.\n * It is parsed once: Kubb builds from the parsed object, and the same document places diagnostics\n * and mappings. Nothing is written: the build runs into a memory storage. A failed build returns\n * an empty module with the error-level diagnostics placed on the spec key they point at.\n */\nexport async function transform({ fileName, content }: TransformParams, { arrayType }: Options = {}): 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 storage = memoryStorage()\n const kubb = createKubb({\n root: dirname(fileName),\n input: document.toJS(),\n output: { path: '.kubb', format: false, lint: false },\n adapter: adapterOas(),\n parsers: [parserTs()],\n plugins: [pluginTs({ arrayType, output: { path: 'index.ts' } })],\n storage,\n })\n\n const targets: Targets = { schemas: new Map(), operations: new Map() }\n kubb.hooks.hook('kubb:generate:schema', (node, { resolver }) => {\n if (node.name) targets.schemas.set(resolver.name(node.name), node.name)\n })\n kubb.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 { diagnostics } = await kubb.safeBuild()\n const errors = diagnostics.filter(Diagnostics.isProblem).filter((diagnostic) => diagnostic.severity === 'error')\n const [key] = await storage.readKeys()\n const text = key ? await storage.readItem(key) : null\n\n const locate = createLocator(document)\n\n if (errors.length || !text) {\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 return { text, extension: '.ts', mappings: createMappings(text, (pointer) => locate({ pointer }), targets) }\n}\n","import { cacheTransform } from './cache.ts'\nimport { type Options, parseOptions } from './options.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\nconst projects = new Map<string, Options>()\n\nconst cachedTransform = cacheTransform(transform)\n\nconst handlers: Record<string, (params: never) => unknown> = {\n initialize: () => ({ protocolVersion: 1, positionEncoding: 'utf-16', diagnosticSource: 'kubb' }),\n openProject: ({ projectHandle, options }: { projectHandle: string; options?: unknown }) => {\n const parsed = parseOptions(options)\n projects.set(projectHandle, parsed.options)\n\n return parsed.diagnostics.length ? { optionDiagnostics: parsed.diagnostics } : {}\n },\n closeProject: ({ projectHandle }: { projectHandle: string }) => {\n projects.delete(projectHandle)\n return null\n },\n transform: (params: TransformParams & { projectHandle: string }) => cachedTransform(params, projects.get(params.projectHandle)),\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":";;;;;;;;;;;;;;AAQA,SAAgB,eACd,WACkE;CAClE,MAAM,0BAAU,IAAI,IAA4F;CAEhH,QAAQ,QAAQ,UAAU,CAAC,MAAM;EAC/B,MAAM,SAAS,QAAQ,IAAI,OAAO,QAAQ;EAC1C,IAAI,UAAU,OAAO,YAAY,OAAO,WAAW,OAAO,cAAc,QAAQ,WAAW,OAAO,OAAO;EAEzG,MAAM,SAAS,UAAU,QAAQ,OAAO;EACxC,QAAQ,IAAI,OAAO,UAAU;GAAE,SAAS,OAAO;GAAS,WAAW,QAAQ;GAAW;EAAO,CAAC;EAC9F,OAAO,YAAY,QAAQ,OAAO,OAAO,QAAQ,CAAC;EAClD,OAAO;CACT;AACF;;;ACHA,MAAM,aAAa,CAAC,SAAS,SAAS;;;;;AAMtC,SAAgB,aAAa,KAA0E;CACrG,MAAM,UAAmB,CAAC;CAC1B,MAAM,cAAuC,CAAC;CAE9C,IAAI,QAAQ,KAAA,KAAa,QAAQ,MAAM,OAAO;EAAE;EAAS;CAAY;CACrE,IAAI,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAC9C,OAAO;EAAE;EAAS,aAAa,CAAC;GAAE,MAAM,CAAC;GAAG,aAAa;EAAsC,CAAC;CAAE;CAGpG,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAAG;EAC9C,IAAI,QAAQ,aAAa;GACvB,YAAY,KAAK;IAAE,MAAM,CAAC,GAAG;IAAG,aAAa,mBAAmB,IAAI;GAA0B,CAAC;GAC/F;EACF;EACA,IAAI,OAAO,UAAU,YAAY,CAAC,WAAW,SAAS,KAAK,GAAG;GAC5D,YAAY,KAAK;IAAE,MAAM,CAAC,GAAG;IAAG,aAAa,qCAAqC,WAAW,KAAK,SAAS,IAAI,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;GAAG,CAAC;GACvI;EACF;EACA,QAAQ,YAAY;CACtB;CAEA,OAAO;EAAE;EAAS;CAAY;AAChC;;;ACpCA,MAAM,YAAY;;;;AAKlB,SAAgB,OAAO,SAA0B;CAC/C,MAAM,OAAO,OAAO,KAAK,KAAK,UAAU;EAAE,SAAS;EAAO,GAAG;CAAQ,CAAC,CAAC;CAEvE,OAAO,OAAO,OAAO,CAAC,OAAO,KAAK,mBAAmB,KAAK,SAAS,WAAW,GAAG,IAAI,CAAC;AACxF;;;;;AAMA,SAAgB,cAAc,WAAgE;CAC5F,IAAI,SAAS,OAAO,MAAM,CAAC;CAE3B,QAAQ,UAAU;EAChB,SAAS,OAAO,OAAO,CAAC,QAAQ,KAAK,CAAC;EAEtC,OAAO,MAAM;GACX,MAAM,YAAY,OAAO,QAAQ,SAAS;GAC1C,IAAI,cAAc,IAAI;GAEtB,MAAM,SAAS,OAAO,SAAS,GAAG,SAAS,CAAC,CAAC,SAAS;GACtD,MAAM,SAAS,OAAO,2BAA2B,KAAK,MAAM,CAAC,GAAG,EAAE;GAClE,IAAI,CAAC,OAAO,UAAU,MAAM,GAAG,MAAM,IAAI,MAAM,qCAAqC,OAAO,EAAE;GAE7F,MAAM,QAAQ,YAAY;GAC1B,IAAI,OAAO,SAAS,QAAQ,QAAQ;GAEpC,MAAM,OAAO,OAAO,SAAS,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS;GAC7D,SAAS,OAAO,SAAS,QAAQ,MAAM;GACvC,UAAU,KAAK,MAAM,IAAI,CAAY;EACvC;CACF;AACF;;;ACzCA,MAAM,WAAW,CAAC,OAAO,UAA6B;CAAE;CAAO;AAAI;AAEnE,MAAM,iBAAiB,UAAkB,MAAM,WAAW,MAAM,GAAG,CAAC,CAAC,WAAW,MAAM,GAAG;;AAGzF,SAAS,YAAY,UAAyB,SAAoC;CAEhF,OADe,QAAQ,QAAQ,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,aACrD,CAAC,CAAC,QACX,IAAI,UAAU;EACb,IAAI,KAAK,MAAM,IAAI,IAAI,GAAG;GACxB,MAAM,OAAO,GAAG,KAAK,MAAM,MAAM,SAAS,KAAK,SAAS,KAAK,GAAG,KAAK,OAAO,KAAK,IAAI,KAAK,MAAM,KAAK;GACrG,OAAO,QAAQ,KAAK,SAAS,KAAK,GAAG,KAAK,KAAK,IAAI,QAAQ;IAAE,MAAM,KAAK;IAAO,OAAO,QAAQ,KAAK,IAAI,KAAK;GAAE,IAAI,KAAA;EACpH;EACA,IAAI,KAAK,MAAM,IAAI,IAAI,GAAG;GACxB,MAAM,OAAO,GAAG,KAAK,MAAM,OAAO,KAAK;GACvC,OAAO,KAAK,OAAO,IAAI,KAAK,KAAK,QAAQ;IAAE,MAAM;IAAM,OAAO,QAAQ,KAAK,KAAK;GAAE,IAAI,KAAA;EACxF;CAEF,GACA;EAAE,MAAM,SAAS;EAAU,OAAO,KAAA;CAAU,CAC9C,CAAC,EAAE;AACL;;AAGA,SAAS,aAAa,UAAyB,KAAgC;CAC7E,IAAI;CACJ,KAAK,MAAM,UAAU,EACnB,KAAK,GAAG,EAAE,KAAK,SAAS;EACtB,IAAI,CAAC,KAAK,SAAS,GAAG,KAAK,IAAI,UAAU,UAAU,CAAC,KAAK,SAAS,KAAK,KAAK,MAAM,UAAU,OAAO,CAAC,MAAM,OAAO;EACjH,QAAQ,QAAQ,MAAM,KAAK;EAC3B,OAAO,KAAK,MAAM;CACpB,EACF,CAAC;CACD,OAAO;AACT;;;;;;AAOA,SAAgB,cAAc,UAA6F;CACzH,QAAQ,EAAE,SAAS,UAAU,YAAY,UAAU,OAAO,MAAM,MAAM,aAAa,UAAU,GAAG,IAAI,KAAA;AACtG;;;AC1BA,MAAM,YAAY;AAGlB,MAAM,WAAW;AAEjB,MAAM,eAAe,UAAkB,MAAM,WAAW,KAAK,IAAI,CAAC,CAAC,WAAW,KAAK,IAAI;;;;;AAMvF,SAAS,iBAAiB,MAAc,QAAwB;CAC9D,MAAM,SAAS,yBAAyB,KAAK,MAAM,CAAC,GAAG;CACvD,IAAI,QAAQ,OAAO,GAAG,KAAK,aAAa,WAAW,YAAY,YAAY;CAC3E,IAAI,uBAAuB,KAAK,MAAM,GAAG,OAAO,GAAG,KAAK;CACxD,IAAI,kCAAkC,KAAK,MAAM,GAAG,OAAO,GAAG,KAAK;CACnE,OAAO;AACT;AAEA,MAAM,iBAAiB,MAAwB,SAAiB,CAAC,GAAG,IAAI,CAAC,CAAC,QAAQ,QAAQ,KAAK,WAAW,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;;;;;AAMpJ,SAAS,oBAAoB,MAAc,EAAE,SAAS,cAAsC;CAC1F,MAAM,SAAS,QAAQ,IAAI,IAAI;CAC/B,IAAI,QAAQ,OAAO,CAAC,wBAAwB,YAAY,MAAM,GAAG;CAEjE,MAAM,eAAe,cAAc,QAAQ,KAAK,GAAG,IAAI;CACvD,MAAM,kBAAkB,cAAc,WAAW,KAAK,GAAG,IAAI;CAE7D,IAAI,iBAAiB,KAAA,MAAc,oBAAoB,KAAA,KAAa,aAAa,SAAS,gBAAgB,SAAS;EACjH,MAAM,OAAO,wBAAwB,YAAY,QAAQ,IAAI,YAAY,CAAE;EAC3E,MAAM,WAAW,KAAK,MAAM,aAAa,MAAM,CAAC,CAAC,QAAQ,qBAAqB,EAAE;EAChF,OAAO,WAAW,CAAC,GAAG,KAAK,cAAc,YAAY,SAAS,EAAE,CAAE,YAAY,IAAI,SAAS,MAAM,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI;CACvH;CACA,IAAI,oBAAoB,KAAA,GAAW,OAAO,CAAC;CAE3C,MAAM,EAAE,MAAM,WAAW,WAAW,IAAI,eAAe;CACvD,OAAO,CAAC,iBAAiB,WAAW,YAAY,IAAI,EAAE,GAAG,OAAO,YAAY,KAAK,KAAK,MAAM,gBAAgB,MAAM,CAAC,CAAC;AACtH;;AAGA,SAAS,cAAc,MAAyF;CAC9G,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,IAAI,GAAG,kBAAkB,IAAI,GAAG,OAAO;EAAE,MAAM;EAAM,OAAO;CAAM;CAClE,IAAI,GAAG,gBAAgB,IAAI,KAAK,GAAG,kBAAkB,KAAK,WAAW,GAAG,OAAO;EAAE,MAAM,KAAK;EAAa,OAAO;CAAK;CACrH,IAAI,GAAG,oBAAoB,IAAI,KAAK,KAAK,SAAS,QAAQ,MAAM,WAAW,KAAK,gBAAgB,MAAM,GAAG,kBAAkB,KAAK,cAAc,EAAE,GAC9I,OAAO;EAAE,MAAM,KAAK,cAAc;EAAI,OAAO;CAAK;AAGtD;;AAGA,SAAS,YAAY,WAAwG;CAC3H,IAAI,GAAG,uBAAuB,SAAS,GAAG,OAAO,UAAU;CAC3D,OAAO,GAAG,kBAAkB,UAAU,IAAI,IAAI,UAAU,KAAK,UAAU,KAAA;AACzE;;;;;;;;;;AAWA,SAAgB,eAAe,MAAc,QAAgB,SAAkC;CAC7F,MAAM,aAAa,GAAG,iBAAiB,YAAY,MAAM,GAAG,aAAa,QAAQ,IAAI;CACrF,MAAM,WAA2B,CAAC;CAElC,MAAM,OAAO,MAAe,GAAG,aAA4B;EACzD,MAAM,QAAQ,SAAS,IAAI,MAAM,CAAC,CAAC,KAAK,OAAO;EAC/C,IAAI,OAAO,SAAS,KAAK;GAAC,KAAK,SAAS,UAAU;GAAG,KAAK,SAAS,UAAU;GAAG,MAAM;GAAO,MAAM,MAAM,MAAM;GAAO;GAAW;EAAQ,CAAC;CAC5I;CAEA,MAAM,cAAc,SAAuC,YAAoB;EAC7E,KAAK,MAAM,UAAU,SAAS;GAC5B,IAAI,CAAC,GAAG,oBAAoB,MAAM,KAAK,EAAE,GAAG,aAAa,OAAO,IAAI,KAAK,GAAG,gBAAgB,OAAO,IAAI,IAAI;GAC3G,MAAM,kBAAkB,GAAG,QAAQ,cAAc,YAAY,OAAO,KAAK,IAAI;GAC7E,IAAI,OAAO,MAAM,eAAe;GAChC,MAAM,UAAU,cAAc,OAAO,IAAI;GACzC,IAAI,SAAS,WAAW,QAAQ,KAAK,SAAS,QAAQ,QAAQ,GAAG,gBAAgB,UAAU,eAAe;EAC5G;CACF;CAEA,KAAK,MAAM,aAAa,WAAW,YAAY;EAC7C,IAAI,GAAG,oBAAoB,SAAS,GAAG;GAErC,KAAK,MAAM,eAAe,UAAU,gBAAgB,cAAc;IAChE,IAAI,CAAC,GAAG,aAAa,YAAY,IAAI,GAAG;IACxC,MAAM,OAAO,YAAY,KAAK;IAC9B,IAAI,YAAY,MAAM,GAAG,oBAAoB,KAAK,EAAE,CAAE,YAAY,IAAI,KAAK,MAAM,CAAC,GAAG,OAAO,CAAC;GAC/F;GACA;EACF;EACA,IAAI,CAAC,GAAG,uBAAuB,SAAS,KAAK,CAAC,GAAG,uBAAuB,SAAS,GAAG;EACpF,MAAM,WAAW,oBAAoB,UAAU,KAAK,MAAM,OAAO;EACjE,IAAI,UAAU,MAAM,GAAG,QAAQ;EAG/B,MAAM,UAAU,SAAS;EACzB,IAAI,CAAC,WAAW,CAAC,QAAQ,QAAQ,IAAI,UAAU,KAAK,IAAI,GAAG;EAC3D,MAAM,UAAU,YAAY,SAAS;EACrC,IAAI,SAAS,WAAW,SAAS,OAAO;CAC1C;CAEA,OAAO;AACT;;;;;;;;;;;ACjGA,eAAsB,UAAU,EAAE,UAAU,WAA4B,EAAE,cAAuB,CAAC,GAA6B;CAC7H,MAAM,WAAW,cAAc,OAAO;CACtC,IAAI,SAAS,OAAO,QAClB,OAAO;EACL,MAAM;EACN,WAAW;EACX,aAAa,SAAS,OAAO,KAAK,WAAW;GAAE,aAAa,MAAM;GAAS,OAAO,MAAM,IAAI;GAAI,QAAQ,MAAM,IAAI,KAAK,MAAM,IAAI;EAAG,EAAE;CACxI;CAGF,MAAM,UAAU,cAAc;CAC9B,MAAM,OAAO,WAAW;EACtB,MAAM,QAAQ,QAAQ;EACtB,OAAO,SAAS,KAAK;EACrB,QAAQ;GAAE,MAAM;GAAS,QAAQ;GAAO,MAAM;EAAM;EACpD,SAAS,WAAW;EACpB,SAAS,CAAC,SAAS,CAAC;EACpB,SAAS,CAAC,SAAS;GAAE;GAAW,QAAQ,EAAE,MAAM,WAAW;EAAE,CAAC,CAAC;EAC/D;CACF,CAAC;CAED,MAAM,UAAmB;EAAE,yBAAS,IAAI,IAAI;EAAG,4BAAY,IAAI,IAAI;CAAE;CACrE,KAAK,MAAM,KAAK,yBAAyB,MAAM,EAAE,eAAe;EAC9D,IAAI,KAAK,MAAM,QAAQ,QAAQ,IAAI,SAAS,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI;CACxE,CAAC;CACD,KAAK,MAAM,KAAK,4BAA4B,MAAM,EAAE,eAAe;EACjE,IAAI,UAAU,QAAQ,KAAK,QAAQ,KAAK,QAAQ,QAAQ,WAAW,IAAI,SAAS,KAAK,KAAK,WAAW,GAAG;GAAE,MAAM,KAAK;GAAM,QAAQ,KAAK;EAAO,CAAC;CAClJ,CAAC;CAED,MAAM,EAAE,gBAAgB,MAAM,KAAK,UAAU;CAC7C,MAAM,SAAS,YAAY,OAAO,YAAY,SAAS,CAAC,CAAC,QAAQ,eAAe,WAAW,aAAa,OAAO;CAC/G,MAAM,CAAC,OAAO,MAAM,QAAQ,SAAS;CACrC,MAAM,OAAO,MAAM,MAAM,QAAQ,SAAS,GAAG,IAAI;CAEjD,MAAM,SAAS,cAAc,QAAQ;CAErC,IAAI,OAAO,UAAU,CAAC,MACpB,OAAO;EACL,MAAM;EACN,WAAW;EACX,aAAa,OAAO,KAAK,UAAU;GACjC,MAAM,QAAQ,MAAM,YAAY,aAAa,MAAM,WAAW,OAAO,MAAM,QAAQ,IAAI,KAAA;GACvF,OAAO;IAAE,aAAa,MAAM;IAAS,OAAO,OAAO,SAAS;IAAG,QAAQ,QAAQ,MAAM,MAAM,MAAM,QAAQ;GAAE;EAC7G,CAAC;CACH;CAGF,OAAO;EAAE;EAAM,WAAW;EAAO,UAAU,eAAe,OAAO,YAAY,OAAO,EAAE,QAAQ,CAAC,GAAG,OAAO;CAAE;AAC7G;;;AC9EA,MAAM,gBAAgB,QAAQ,OAAO,MAAM,KAAK,QAAQ,MAAM;AAC9D,QAAQ,OAAO,QAAQ,QAAQ,OAAO,MAAM,KAAK,QAAQ,MAAM;AAE/D,MAAM,2BAAW,IAAI,IAAqB;AAE1C,MAAM,kBAAkB,eAAe,SAAS;AAEhD,MAAM,WAAuD;CAC3D,mBAAmB;EAAE,iBAAiB;EAAG,kBAAkB;EAAU,kBAAkB;CAAO;CAC9F,cAAc,EAAE,eAAe,cAA4D;EACzF,MAAM,SAAS,aAAa,OAAO;EACnC,SAAS,IAAI,eAAe,OAAO,OAAO;EAE1C,OAAO,OAAO,YAAY,SAAS,EAAE,mBAAmB,OAAO,YAAY,IAAI,CAAC;CAClF;CACA,eAAe,EAAE,oBAA+C;EAC9D,SAAS,OAAO,aAAa;EAC7B,OAAO;CACT;CACA,YAAY,WAAwD,gBAAgB,QAAQ,SAAS,IAAI,OAAO,aAAa,CAAC;AAChI;AAEA,eAAe,OAAO,EAAE,IAAI,SAAS,IAAI,UAAkC;CACzE,MAAM,UAAU,SAAS;CACzB,IAAI,OAAO,KAAA,GAAW;CAEtB,IAAI;EACF,IAAI,CAAC,SAAS;GACZ,cAAc,OAAO;IAAE;IAAI,OAAO;KAAE,MAAM;KAAQ,SAAS,mBAAmB,OAAO;IAAG;GAAE,CAAC,CAAC;GAC5F;EACF;EACA,MAAM,SAAS,MAAM,QAAQ,MAAe;EAC5C,cAAc,OAAO;GAAE;GAAI,QAAQ,UAAU;EAAK,CAAC,CAAC;CACtD,SAAS,OAAO;EACd,cAAc,OAAO;GAAE;GAAI,OAAO;IAAE,MAAM;IAAQ,SAAS,iBAAiB,QAAS,MAAM,SAAS,MAAM,UAAW,OAAO,KAAK;GAAE;EAAE,CAAC,CAAC;CACzI;AACF;AAEA,QAAQ,MAAM,GACZ,QACA,eAAe,YAAY,KAAK,OAAO,OAAO,CAAC,CACjD"}
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 * 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(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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-import",
3
- "version": "0.0.0",
3
+ "version": "0.0.2",
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",
@@ -48,44 +48,31 @@
48
48
  "access": "public",
49
49
  "registry": "https://registry.npmjs.org/"
50
50
  },
51
- "scripts": {
52
- "build": "tsdown",
53
- "changeset": "changeset",
54
- "clean": "node -e \"require('node:fs').rmSync('./dist', {recursive:true,force:true})\"",
55
- "format": "oxfmt -c oxfmt.config.ts .",
56
- "format:check": "oxfmt -c oxfmt.config.ts --check .",
57
- "lint": "oxlint -c oxlint.config.ts .",
58
- "lint:fix": "oxlint -c oxlint.config.ts --fix .",
59
- "start": "tsdown --watch",
60
- "test": "vitest run",
61
- "typecheck": "tsc",
62
- "typecheck:example": "pnpm --filter openapi-import-pet-store typecheck"
63
- },
64
51
  "dependencies": {
65
- "@kubb/adapter-oas": "^5.12.5",
66
- "@kubb/core": "^5.12.5",
67
- "@kubb/parser-ts": "^5.12.5",
68
52
  "@kubb/plugin-ts": "^5.0.14",
69
53
  "@typescript/typescript6": "^6.0.2",
54
+ "unplugin-kubb": "^5.12.6",
70
55
  "yaml": "^2.9.1"
71
56
  },
72
57
  "devDependencies": {
73
58
  "@changesets/changelog-github": "^1.0.1",
74
59
  "@changesets/cli": "^3.0.3",
60
+ "@kubb/plugin-zod": "^5.4.12",
75
61
  "@types/node": "22.20.2",
76
62
  "@vitest/coverage-v8": "^5.0.5",
77
- "kubb": "^5.12.5",
63
+ "kubb": "^5.12.6",
78
64
  "oxfmt": "^0.72.0",
79
65
  "oxlint": "^1.88.0",
80
66
  "tsdown": "^0.23.1",
81
- "typescript": "^7.0.2",
67
+ "typescript": "7.1.0-beta",
82
68
  "vitest": "^5.0.5"
83
69
  },
84
70
  "peerDependencies": {
85
- "kubb": "^5.12.5"
71
+ "kubb": "^5.12.6"
86
72
  },
87
73
  "typescript": {
88
74
  "contentMapper": {
75
+ "dynamicConfig": true,
89
76
  "exec": [
90
77
  "node",
91
78
  "dist/server.js"
@@ -96,5 +83,17 @@
96
83
  "node": ">=22.12",
97
84
  "pnpm": ">=11.0.0"
98
85
  },
99
- "packageManager": "pnpm@12.11.2"
100
- }
86
+ "scripts": {
87
+ "build": "tsdown",
88
+ "changeset": "changeset",
89
+ "clean": "node -e \"require('node:fs').rmSync('./dist', {recursive:true,force:true})\"",
90
+ "format": "oxfmt -c oxfmt.config.ts .",
91
+ "format:check": "oxfmt -c oxfmt.config.ts --check .",
92
+ "lint": "oxlint -c oxlint.config.ts .",
93
+ "lint:fix": "oxlint -c oxlint.config.ts --fix .",
94
+ "start": "tsdown --watch",
95
+ "test": "vitest run",
96
+ "typecheck": "tsc",
97
+ "typecheck:example": "pnpm --filter openapi-import-pet-store typecheck"
98
+ }
99
+ }