@warlock.js/core 5.26.0 → 5.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/esm/cli/commands/openapi-generator.action.mjs +43 -0
  3. package/esm/cli/commands/openapi-generator.action.mjs.map +1 -0
  4. package/esm/cli/commands/openapi-generator.command.mjs +44 -0
  5. package/esm/cli/commands/openapi-generator.command.mjs.map +1 -0
  6. package/esm/cli/commands/postman-generator.action.mjs +47 -0
  7. package/esm/cli/commands/postman-generator.action.mjs.map +1 -0
  8. package/esm/cli/commands/postman-generator.command.mjs +43 -0
  9. package/esm/cli/commands/postman-generator.command.mjs.map +1 -0
  10. package/esm/cli/framework-cli-commands.mjs +4 -0
  11. package/esm/cli/framework-cli-commands.mjs.map +1 -1
  12. package/esm/dev-server/build-development-openapi-document.mjs +36 -0
  13. package/esm/dev-server/build-development-openapi-document.mjs.map +1 -0
  14. package/esm/dev-server/collect-development-api-routes.mjs +27 -0
  15. package/esm/dev-server/collect-development-api-routes.mjs.map +1 -0
  16. package/esm/dev-server/dev-logger.mjs +9 -1
  17. package/esm/dev-server/dev-logger.mjs.map +1 -1
  18. package/esm/dev-server/development-server.mjs +6 -3
  19. package/esm/dev-server/development-server.mjs.map +1 -1
  20. package/esm/dev-server/files-orchestrator.mjs +17 -1
  21. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  22. package/esm/dev-server/model-resource-typings.mjs +246 -0
  23. package/esm/dev-server/model-resource-typings.mjs.map +1 -0
  24. package/esm/dev-server/type-generator.mjs +46 -2
  25. package/esm/dev-server/type-generator.mjs.map +1 -1
  26. package/esm/http/index.d.mts +2 -1
  27. package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
  28. package/esm/http/middleware/inject-request-context.mjs +29 -3
  29. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  30. package/esm/http/serialized.d.mts +114 -0
  31. package/esm/http/serialized.d.mts.map +1 -0
  32. package/esm/index.d.mts +11 -3
  33. package/esm/index.mjs +6 -1
  34. package/esm/openapi/build-openapi-document.d.mts +17 -0
  35. package/esm/openapi/build-openapi-document.d.mts.map +1 -0
  36. package/esm/openapi/build-openapi-document.mjs +124 -0
  37. package/esm/openapi/build-openapi-document.mjs.map +1 -0
  38. package/esm/openapi/cast-schema.mjs +89 -0
  39. package/esm/openapi/cast-schema.mjs.map +1 -0
  40. package/esm/openapi/collect-openapi-document.mjs +40 -0
  41. package/esm/openapi/collect-openapi-document.mjs.map +1 -0
  42. package/esm/openapi/development-openapi-provider.d.mts +28 -0
  43. package/esm/openapi/development-openapi-provider.d.mts.map +1 -0
  44. package/esm/openapi/development-openapi-provider.mjs +35 -0
  45. package/esm/openapi/development-openapi-provider.mjs.map +1 -0
  46. package/esm/openapi/error-responses.mjs +67 -0
  47. package/esm/openapi/error-responses.mjs.map +1 -0
  48. package/esm/openapi/index.d.mts +6 -0
  49. package/esm/openapi/index.mjs +6 -0
  50. package/esm/openapi/openapi-child-output.mjs +57 -0
  51. package/esm/openapi/openapi-child-output.mjs.map +1 -0
  52. package/esm/openapi/openapi-protocol.mjs +30 -0
  53. package/esm/openapi/openapi-protocol.mjs.map +1 -0
  54. package/esm/openapi/paths.mjs +63 -0
  55. package/esm/openapi/paths.mjs.map +1 -0
  56. package/esm/openapi/postman/build-request-body.mjs +86 -0
  57. package/esm/openapi/postman/build-request-body.mjs.map +1 -0
  58. package/esm/openapi/postman/build-request-url.mjs +85 -0
  59. package/esm/openapi/postman/build-request-url.mjs.map +1 -0
  60. package/esm/openapi/postman/build-saved-responses.mjs +60 -0
  61. package/esm/openapi/postman/build-saved-responses.mjs.map +1 -0
  62. package/esm/openapi/postman/example-from-schema.d.mts +17 -0
  63. package/esm/openapi/postman/example-from-schema.d.mts.map +1 -0
  64. package/esm/openapi/postman/example-from-schema.mjs +92 -0
  65. package/esm/openapi/postman/example-from-schema.mjs.map +1 -0
  66. package/esm/openapi/postman/http-status-text.mjs +31 -0
  67. package/esm/openapi/postman/http-status-text.mjs.map +1 -0
  68. package/esm/openapi/postman/index.d.mts +3 -0
  69. package/esm/openapi/postman/openapi-to-postman-collection.d.mts +22 -0
  70. package/esm/openapi/postman/openapi-to-postman-collection.d.mts.map +1 -0
  71. package/esm/openapi/postman/openapi-to-postman-collection.mjs +109 -0
  72. package/esm/openapi/postman/openapi-to-postman-collection.mjs.map +1 -0
  73. package/esm/openapi/postman/postman-types.d.mts +119 -0
  74. package/esm/openapi/postman/postman-types.d.mts.map +1 -0
  75. package/esm/openapi/postman/resolve-operation-auth.mjs +51 -0
  76. package/esm/openapi/postman/resolve-operation-auth.mjs.map +1 -0
  77. package/esm/openapi/postman/schema-refs.d.mts +7 -0
  78. package/esm/openapi/postman/schema-refs.d.mts.map +1 -0
  79. package/esm/openapi/postman/schema-refs.mjs +41 -0
  80. package/esm/openapi/postman/schema-refs.mjs.map +1 -0
  81. package/esm/openapi/postman/uuid-v5.mjs +29 -0
  82. package/esm/openapi/postman/uuid-v5.mjs.map +1 -0
  83. package/esm/openapi/request-schemas.mjs +138 -0
  84. package/esm/openapi/request-schemas.mjs.map +1 -0
  85. package/esm/openapi/response-schemas.mjs +85 -0
  86. package/esm/openapi/response-schemas.mjs.map +1 -0
  87. package/esm/openapi/schema-registry.mjs +143 -0
  88. package/esm/openapi/schema-registry.mjs.map +1 -0
  89. package/esm/openapi/security.mjs +98 -0
  90. package/esm/openapi/security.mjs.map +1 -0
  91. package/esm/openapi/types.d.mts +119 -0
  92. package/esm/openapi/types.d.mts.map +1 -0
  93. package/esm/production/registration-child-runner.mjs +139 -0
  94. package/esm/production/registration-child-runner.mjs.map +1 -0
  95. package/esm/production/route-registration-child.mjs +30 -2
  96. package/esm/production/route-registration-child.mjs.map +1 -1
  97. package/esm/production/route-registration-snapshot.mjs +22 -119
  98. package/esm/production/route-registration-snapshot.mjs.map +1 -1
  99. package/esm/resource/define-resource.d.mts +44 -14
  100. package/esm/resource/define-resource.d.mts.map +1 -1
  101. package/esm/resource/define-resource.mjs +0 -40
  102. package/esm/resource/define-resource.mjs.map +1 -1
  103. package/esm/resource/index.d.mts +1 -1
  104. package/esm/resource/resource.d.mts +4 -4
  105. package/esm/resource/resource.d.mts.map +1 -1
  106. package/esm/resource/resource.mjs +2 -4
  107. package/esm/resource/resource.mjs.map +1 -1
  108. package/esm/resource/types.d.mts +89 -4
  109. package/esm/resource/types.d.mts.map +1 -1
  110. package/esm/router/index.d.mts +1 -1
  111. package/esm/router/named-api-routes-with-responses.mjs +59 -0
  112. package/esm/router/named-api-routes-with-responses.mjs.map +1 -0
  113. package/esm/router/response-schema-types.mjs +100 -0
  114. package/esm/router/response-schema-types.mjs.map +1 -0
  115. package/esm/router/router.d.mts +2 -2
  116. package/esm/router/router.d.mts.map +1 -1
  117. package/esm/router/router.mjs +38 -11
  118. package/esm/router/router.mjs.map +1 -1
  119. package/esm/router/types.d.mts +16 -1
  120. package/esm/router/types.d.mts.map +1 -1
  121. package/llms-full.txt +293 -5
  122. package/llms.txt +3 -2
  123. package/package.json +13 -13
  124. package/skills/README.md +3 -2
  125. package/skills/create-controller/SKILL.md +39 -2
  126. package/skills/define-resource/SKILL.md +100 -1
  127. package/skills/generate-openapi/SKILL.md +148 -0
  128. package/skills/index.md +3 -3
  129. package/skills/validate-input/SKILL.md +2 -2
@@ -0,0 +1,63 @@
1
+ //#region ../core/src/openapi/paths.ts
2
+ /**
3
+ * The concrete verbs an `all` route expands into. Mirrors `ALL_METHODS` in the route registry.
4
+ */
5
+ const ALL_METHODS = [
6
+ "get",
7
+ "post",
8
+ "put",
9
+ "patch",
10
+ "delete",
11
+ "options",
12
+ "head"
13
+ ];
14
+ const PATH_PARAM_PATTERN = /:([A-Za-z_][A-Za-z0-9_]*)(\([^)]*\))?/g;
15
+ /**
16
+ * Convert a Warlock path into an OpenAPI path template: `/users/:id` -> `/users/{id}`.
17
+ * A Fastify-style regex suffix (`:id(\d+)`) is dropped.
18
+ */
19
+ function toOpenApiPath(path) {
20
+ return path.replace(PATH_PARAM_PATTERN, (_match, name) => `{${name}}`);
21
+ }
22
+ /**
23
+ * Names of the path parameters of a Warlock path, in order of appearance.
24
+ */
25
+ function extractPathParamNames(path) {
26
+ return [...path.matchAll(PATH_PARAM_PATTERN)].flatMap((match) => match[1] ?? []);
27
+ }
28
+ /**
29
+ * Lowercase operation verbs of a route method; `all` expands to every verb.
30
+ */
31
+ function expandMethods(method) {
32
+ const lowered = String(method).toLowerCase();
33
+ if (lowered === "all") return [...ALL_METHODS];
34
+ return ALL_METHODS.includes(lowered) ? [lowered] : [];
35
+ }
36
+ /**
37
+ * `operationId` for an operation. A named route keeps its name (with `.<verb>` appended when
38
+ * an `all` route expands into several operations); an unnamed route gets a `method_path_slug`
39
+ * id such as `get_users_id`.
40
+ */
41
+ function buildOperationId(name, method, path, expanded) {
42
+ if (name) return expanded ? `${name}.${method}` : name;
43
+ const slug = path.replace(PATH_PARAM_PATTERN, "$1").replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
44
+ return slug ? `${method}_${slug}` : method;
45
+ }
46
+ /**
47
+ * Tag of a route: its first static path segment (`/users/:id` -> `users`).
48
+ */
49
+ function firstSegmentTag(path) {
50
+ const segment = path.split("/").find((part) => part.length > 0);
51
+ if (!segment || segment.startsWith(":") || segment === "*") return;
52
+ return segment;
53
+ }
54
+ /**
55
+ * Verbs whose requests carry no body, so unscoped validation maps to query parameters.
56
+ */
57
+ function isBodylessMethod(method) {
58
+ return method === "get" || method === "head" || method === "delete" || method === "options";
59
+ }
60
+
61
+ //#endregion
62
+ export { buildOperationId, expandMethods, extractPathParamNames, firstSegmentTag, isBodylessMethod, toOpenApiPath };
63
+ //# sourceMappingURL=paths.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.mjs","names":[],"sources":["../../../../../../../core/src/openapi/paths.ts"],"sourcesContent":["import type { RequestMethod } from \"../router/types\";\n\n/**\n * The concrete verbs an `all` route expands into. Mirrors `ALL_METHODS` in the route registry.\n */\nconst ALL_METHODS = [\"get\", \"post\", \"put\", \"patch\", \"delete\", \"options\", \"head\"] as const;\n\nexport type OpenApiMethod = (typeof ALL_METHODS)[number];\n\nconst PATH_PARAM_PATTERN = /:([A-Za-z_][A-Za-z0-9_]*)(\\([^)]*\\))?/g;\n\n/**\n * Convert a Warlock path into an OpenAPI path template: `/users/:id` -> `/users/{id}`.\n * A Fastify-style regex suffix (`:id(\\d+)`) is dropped.\n */\nexport function toOpenApiPath(path: string): string {\n return path.replace(PATH_PARAM_PATTERN, (_match, name: string) => `{${name}}`);\n}\n\n/**\n * Names of the path parameters of a Warlock path, in order of appearance.\n */\nexport function extractPathParamNames(path: string): string[] {\n return [...path.matchAll(PATH_PARAM_PATTERN)].flatMap((match) => match[1] ?? []);\n}\n\n/**\n * Lowercase operation verbs of a route method; `all` expands to every verb.\n */\nexport function expandMethods(method: RequestMethod | string): OpenApiMethod[] {\n const lowered = String(method).toLowerCase();\n\n if (lowered === \"all\") {\n return [...ALL_METHODS];\n }\n\n return (ALL_METHODS as readonly string[]).includes(lowered) ? [lowered as OpenApiMethod] : [];\n}\n\n/**\n * `operationId` for an operation. A named route keeps its name (with `.<verb>` appended when\n * an `all` route expands into several operations); an unnamed route gets a `method_path_slug`\n * id such as `get_users_id`.\n */\nexport function buildOperationId(\n name: string | undefined,\n method: OpenApiMethod,\n path: string,\n expanded: boolean,\n): string {\n if (name) {\n return expanded ? `${name}.${method}` : name;\n }\n\n const slug = path\n .replace(PATH_PARAM_PATTERN, \"$1\")\n .replace(/[^A-Za-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n\n return slug ? `${method}_${slug}` : method;\n}\n\n/**\n * Tag of a route: its first static path segment (`/users/:id` -> `users`).\n */\nexport function firstSegmentTag(path: string): string | undefined {\n const segment = path.split(\"/\").find((part) => part.length > 0);\n\n if (!segment || segment.startsWith(\":\") || segment === \"*\") {\n return undefined;\n }\n\n return segment;\n}\n\n/**\n * Verbs whose requests carry no body, so unscoped validation maps to query parameters.\n */\nexport function isBodylessMethod(method: OpenApiMethod): boolean {\n return method === \"get\" || method === \"head\" || method === \"delete\" || method === \"options\";\n}\n"],"mappings":";;;;AAKA,MAAM,cAAc;CAAC;CAAO;CAAQ;CAAO;CAAS;CAAU;CAAW;AAAM;AAI/E,MAAM,qBAAqB;;;;;AAM3B,SAAgB,cAAc,MAAsB;CAClD,OAAO,KAAK,QAAQ,qBAAqB,QAAQ,SAAiB,IAAI,KAAK,EAAE;AAC/E;;;;AAKA,SAAgB,sBAAsB,MAAwB;CAC5D,OAAO,CAAC,GAAG,KAAK,SAAS,kBAAkB,CAAC,CAAC,CAAC,SAAS,UAAU,MAAM,MAAM,CAAC,CAAC;AACjF;;;;AAKA,SAAgB,cAAc,QAAiD;CAC7E,MAAM,UAAU,OAAO,MAAM,CAAC,CAAC,YAAY;CAE3C,IAAI,YAAY,OACd,OAAO,CAAC,GAAG,WAAW;CAGxB,OAAQ,YAAkC,SAAS,OAAO,IAAI,CAAC,OAAwB,IAAI,CAAC;AAC9F;;;;;;AAOA,SAAgB,iBACd,MACA,QACA,MACA,UACQ;CACR,IAAI,MACF,OAAO,WAAW,GAAG,KAAK,GAAG,WAAW;CAG1C,MAAM,OAAO,KACV,QAAQ,oBAAoB,IAAI,CAAC,CACjC,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,QAAQ,YAAY,EAAE;CAEzB,OAAO,OAAO,GAAG,OAAO,GAAG,SAAS;AACtC;;;;AAKA,SAAgB,gBAAgB,MAAkC;CAChE,MAAM,UAAU,KAAK,MAAM,GAAG,CAAC,CAAC,MAAM,SAAS,KAAK,SAAS,CAAC;CAE9D,IAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,KAAK,YAAY,KACrD;CAGF,OAAO;AACT;;;;AAKA,SAAgB,iBAAiB,QAAgC;CAC/D,OAAO,WAAW,SAAS,WAAW,UAAU,WAAW,YAAY,WAAW;AACpF"}
@@ -0,0 +1,86 @@
1
+ import { isRecord, primaryType, resolveSchema } from "./schema-refs.mjs";
2
+ import { exampleFromSchema } from "./example-from-schema.mjs";
3
+
4
+ //#region ../core/src/openapi/postman/build-request-body.ts
5
+ const MULTIPART = "multipart/form-data";
6
+ const URL_ENCODED = "application/x-www-form-urlencoded";
7
+ function isJsonContentType(contentType) {
8
+ return contentType === "application/json" || contentType.endsWith("+json");
9
+ }
10
+ function stringifyValue(value) {
11
+ if (typeof value === "string") return value;
12
+ return isRecord(value) || Array.isArray(value) ? JSON.stringify(value) : String(value);
13
+ }
14
+ function isFileSchema(schema, components) {
15
+ const resolved = resolveSchema(schema, components);
16
+ if (resolved.format === "binary" || typeof resolved.contentMediaType === "string") return true;
17
+ return primaryType(resolved) === "array" && isRecord(resolved.items) ? isFileSchema(resolved.items, components) : false;
18
+ }
19
+ function formFields(schema, components) {
20
+ const resolved = resolveSchema(schema, components);
21
+ const properties = isRecord(resolved.properties) ? resolved.properties : {};
22
+ return Object.entries(properties).flatMap(([key, property]) => {
23
+ if (!isRecord(property)) return [];
24
+ const description = typeof property.description === "string" ? { description: property.description } : {};
25
+ if (isFileSchema(property, components)) return [{
26
+ key,
27
+ type: "file",
28
+ src: [],
29
+ ...description
30
+ }];
31
+ return [{
32
+ key,
33
+ value: stringifyValue(exampleFromSchema(property, components)),
34
+ type: "text",
35
+ ...description
36
+ }];
37
+ });
38
+ }
39
+ function pickContentType(contentTypes) {
40
+ return contentTypes.find(isJsonContentType) ?? contentTypes.find((contentType) => contentType === MULTIPART) ?? contentTypes.find((contentType) => contentType === URL_ENCODED) ?? contentTypes[0];
41
+ }
42
+ /**
43
+ * The Postman body of an operation's request body: JSON becomes a raw JSON example, multipart
44
+ * becomes `formdata` (binary properties as file rows), url-encoded becomes `urlencoded`.
45
+ *
46
+ * @returns `undefined` when the operation has no usable body.
47
+ */
48
+ function buildRequestBody(requestBody, components) {
49
+ if (!requestBody) return;
50
+ const contentType = pickContentType(Object.keys(requestBody.content));
51
+ const schema = contentType !== void 0 ? requestBody.content[contentType]?.schema : void 0;
52
+ if (contentType === void 0 || schema === void 0) return;
53
+ if (contentType === MULTIPART) return { body: {
54
+ mode: "formdata",
55
+ formdata: formFields(schema, components)
56
+ } };
57
+ if (contentType === URL_ENCODED) return { body: {
58
+ mode: "urlencoded",
59
+ urlencoded: formFields(schema, components).flatMap((field) => field.type === "text" ? [{
60
+ key: field.key,
61
+ value: field.value,
62
+ type: "text"
63
+ }] : [])
64
+ } };
65
+ const example = exampleFromSchema(schema, components);
66
+ if (isJsonContentType(contentType)) return {
67
+ contentType,
68
+ body: {
69
+ mode: "raw",
70
+ raw: JSON.stringify(example, null, 2),
71
+ options: { raw: { language: "json" } }
72
+ }
73
+ };
74
+ return {
75
+ contentType,
76
+ body: {
77
+ mode: "raw",
78
+ raw: typeof example === "string" ? example : "",
79
+ options: { raw: { language: "text" } }
80
+ }
81
+ };
82
+ }
83
+
84
+ //#endregion
85
+ export { buildRequestBody };
86
+ //# sourceMappingURL=build-request-body.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-request-body.mjs","names":[],"sources":["../../../../../../../../core/src/openapi/postman/build-request-body.ts"],"sourcesContent":["import type { OpenApiRequestBody, OpenApiSchema } from \"../types\";\nimport { exampleFromSchema } from \"./example-from-schema\";\nimport type { PostmanBody, PostmanFormParam } from \"./postman-types\";\nimport { isRecord, primaryType, resolveSchema, type SchemaComponents } from \"./schema-refs\";\n\nexport type RequestBodyParts = {\n body: PostmanBody;\n /** Set when the request needs an explicit `Content-Type` header; Postman adds the form ones itself. */\n contentType?: string;\n};\n\nconst MULTIPART = \"multipart/form-data\";\nconst URL_ENCODED = \"application/x-www-form-urlencoded\";\n\nfunction isJsonContentType(contentType: string): boolean {\n return contentType === \"application/json\" || contentType.endsWith(\"+json\");\n}\n\nfunction stringifyValue(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n\n return isRecord(value) || Array.isArray(value) ? JSON.stringify(value) : String(value);\n}\n\nfunction isFileSchema(schema: OpenApiSchema, components: SchemaComponents): boolean {\n const resolved = resolveSchema(schema, components);\n\n if (resolved.format === \"binary\" || typeof resolved.contentMediaType === \"string\") {\n return true;\n }\n\n return primaryType(resolved) === \"array\" && isRecord(resolved.items)\n ? isFileSchema(resolved.items, components)\n : false;\n}\n\nfunction formFields(schema: OpenApiSchema, components: SchemaComponents): PostmanFormParam[] {\n const resolved = resolveSchema(schema, components);\n const properties = isRecord(resolved.properties) ? resolved.properties : {};\n\n return Object.entries(properties).flatMap(([key, property]): PostmanFormParam[] => {\n if (!isRecord(property)) {\n return [];\n }\n\n const description = typeof property.description === \"string\" ? { description: property.description } : {};\n\n if (isFileSchema(property, components)) {\n return [{ key, type: \"file\", src: [], ...description }];\n }\n\n return [{ key, value: stringifyValue(exampleFromSchema(property, components)), type: \"text\", ...description }];\n });\n}\n\nfunction pickContentType(contentTypes: string[]): string | undefined {\n return (\n contentTypes.find(isJsonContentType) ??\n contentTypes.find((contentType) => contentType === MULTIPART) ??\n contentTypes.find((contentType) => contentType === URL_ENCODED) ??\n contentTypes[0]\n );\n}\n\n/**\n * The Postman body of an operation's request body: JSON becomes a raw JSON example, multipart\n * becomes `formdata` (binary properties as file rows), url-encoded becomes `urlencoded`.\n *\n * @returns `undefined` when the operation has no usable body.\n */\nexport function buildRequestBody(\n requestBody: OpenApiRequestBody | undefined,\n components: SchemaComponents,\n): RequestBodyParts | undefined {\n if (!requestBody) {\n return undefined;\n }\n\n const contentType = pickContentType(Object.keys(requestBody.content));\n const schema = contentType !== undefined ? requestBody.content[contentType]?.schema : undefined;\n\n if (contentType === undefined || schema === undefined) {\n return undefined;\n }\n\n if (contentType === MULTIPART) {\n return { body: { mode: \"formdata\", formdata: formFields(schema, components) } };\n }\n\n if (contentType === URL_ENCODED) {\n const urlencoded = formFields(schema, components).flatMap((field) =>\n field.type === \"text\" ? [{ key: field.key, value: field.value, type: \"text\" as const }] : [],\n );\n\n return { body: { mode: \"urlencoded\", urlencoded } };\n }\n\n const example = exampleFromSchema(schema, components);\n\n if (isJsonContentType(contentType)) {\n return {\n contentType,\n body: {\n mode: \"raw\",\n raw: JSON.stringify(example, null, 2),\n options: { raw: { language: \"json\" } },\n },\n };\n }\n\n return {\n contentType,\n body: {\n mode: \"raw\",\n raw: typeof example === \"string\" ? example : \"\",\n options: { raw: { language: \"text\" } },\n },\n };\n}\n"],"mappings":";;;;AAWA,MAAM,YAAY;AAClB,MAAM,cAAc;AAEpB,SAAS,kBAAkB,aAA8B;CACvD,OAAO,gBAAgB,sBAAsB,YAAY,SAAS,OAAO;AAC3E;AAEA,SAAS,eAAe,OAAwB;CAC9C,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,OAAO,SAAS,KAAK,KAAK,MAAM,QAAQ,KAAK,IAAI,KAAK,UAAU,KAAK,IAAI,OAAO,KAAK;AACvF;AAEA,SAAS,aAAa,QAAuB,YAAuC;CAClF,MAAM,WAAW,cAAc,QAAQ,UAAU;CAEjD,IAAI,SAAS,WAAW,YAAY,OAAO,SAAS,qBAAqB,UACvE,OAAO;CAGT,OAAO,YAAY,QAAQ,MAAM,WAAW,SAAS,SAAS,KAAK,IAC/D,aAAa,SAAS,OAAO,UAAU,IACvC;AACN;AAEA,SAAS,WAAW,QAAuB,YAAkD;CAC3F,MAAM,WAAW,cAAc,QAAQ,UAAU;CACjD,MAAM,aAAa,SAAS,SAAS,UAAU,IAAI,SAAS,aAAa,CAAC;CAE1E,OAAO,OAAO,QAAQ,UAAU,CAAC,CAAC,SAAS,CAAC,KAAK,cAAkC;EACjF,IAAI,CAAC,SAAS,QAAQ,GACpB,OAAO,CAAC;EAGV,MAAM,cAAc,OAAO,SAAS,gBAAgB,WAAW,EAAE,aAAa,SAAS,YAAY,IAAI,CAAC;EAExG,IAAI,aAAa,UAAU,UAAU,GACnC,OAAO,CAAC;GAAE;GAAK,MAAM;GAAQ,KAAK,CAAC;GAAG,GAAG;EAAY,CAAC;EAGxD,OAAO,CAAC;GAAE;GAAK,OAAO,eAAe,kBAAkB,UAAU,UAAU,CAAC;GAAG,MAAM;GAAQ,GAAG;EAAY,CAAC;CAC/G,CAAC;AACH;AAEA,SAAS,gBAAgB,cAA4C;CACnE,OACE,aAAa,KAAK,iBAAiB,KACnC,aAAa,MAAM,gBAAgB,gBAAgB,SAAS,KAC5D,aAAa,MAAM,gBAAgB,gBAAgB,WAAW,KAC9D,aAAa;AAEjB;;;;;;;AAQA,SAAgB,iBACd,aACA,YAC8B;CAC9B,IAAI,CAAC,aACH;CAGF,MAAM,cAAc,gBAAgB,OAAO,KAAK,YAAY,OAAO,CAAC;CACpE,MAAM,SAAS,gBAAgB,SAAY,YAAY,QAAQ,YAAY,EAAE,SAAS;CAEtF,IAAI,gBAAgB,UAAa,WAAW,QAC1C;CAGF,IAAI,gBAAgB,WAClB,OAAO,EAAE,MAAM;EAAE,MAAM;EAAY,UAAU,WAAW,QAAQ,UAAU;CAAE,EAAE;CAGhF,IAAI,gBAAgB,aAKlB,OAAO,EAAE,MAAM;EAAE,MAAM;EAAc,YAJlB,WAAW,QAAQ,UAAU,CAAC,CAAC,SAAS,UACzD,MAAM,SAAS,SAAS,CAAC;GAAE,KAAK,MAAM;GAAK,OAAO,MAAM;GAAO,MAAM;EAAgB,CAAC,IAAI,CAAC,CAG/C;CAAE,EAAE;CAGpD,MAAM,UAAU,kBAAkB,QAAQ,UAAU;CAEpD,IAAI,kBAAkB,WAAW,GAC/B,OAAO;EACL;EACA,MAAM;GACJ,MAAM;GACN,KAAK,KAAK,UAAU,SAAS,MAAM,CAAC;GACpC,SAAS,EAAE,KAAK,EAAE,UAAU,OAAO,EAAE;EACvC;CACF;CAGF,OAAO;EACL;EACA,MAAM;GACJ,MAAM;GACN,KAAK,OAAO,YAAY,WAAW,UAAU;GAC7C,SAAS,EAAE,KAAK,EAAE,UAAU,OAAO,EAAE;EACvC;CACF;AACF"}
@@ -0,0 +1,85 @@
1
+ import { isRecord, resolveSchema } from "./schema-refs.mjs";
2
+
3
+ //#region ../core/src/openapi/postman/build-request-url.ts
4
+ /** The Postman variable every request URL starts with. */
5
+ const BASE_URL_HOST = "{{baseUrl}}";
6
+ const PATH_TEMPLATE_PARAM = /\{([^}]+)\}/g;
7
+ function stringifyValue(value) {
8
+ if (typeof value === "string") return value;
9
+ return isRecord(value) || Array.isArray(value) ? JSON.stringify(value) : String(value);
10
+ }
11
+ /**
12
+ * Value a parameter starts with in Postman: its declared `example`, `default`, `const` or
13
+ * first `enum` value, otherwise empty so the caller fills it in.
14
+ */
15
+ function parameterValue(schema, components) {
16
+ const resolved = resolveSchema(schema, components);
17
+ for (const key of [
18
+ "example",
19
+ "default",
20
+ "const"
21
+ ]) if (key in resolved) return stringifyValue(resolved[key]);
22
+ if (Array.isArray(resolved.enum) && resolved.enum.length > 0) return stringifyValue(resolved.enum[0]);
23
+ return "";
24
+ }
25
+ function withDescription(row, parameter) {
26
+ return parameter.description ? {
27
+ ...row,
28
+ description: parameter.description
29
+ } : row;
30
+ }
31
+ function queryRows(parameter, components) {
32
+ const disabled = parameter.required === true ? {} : { disabled: true };
33
+ const schema = resolveSchema(parameter.schema, components);
34
+ if (parameter.style === "deepObject" && isRecord(schema.properties)) return Object.entries(schema.properties).map(([property, propertySchema]) => ({
35
+ key: `${parameter.name}[${property}]`,
36
+ value: isRecord(propertySchema) ? parameterValue(propertySchema, components) : "",
37
+ ...disabled
38
+ }));
39
+ return [{
40
+ key: parameter.name,
41
+ value: parameterValue(parameter.schema, components),
42
+ ...parameter.description ? { description: parameter.description } : {},
43
+ ...disabled
44
+ }];
45
+ }
46
+ /**
47
+ * Header rows for the `header` parameters of an operation. Optional ones start disabled.
48
+ */
49
+ function buildHeaderParameters(parameters, components) {
50
+ return parameters.filter((parameter) => parameter.in === "header").map((parameter) => withDescription({
51
+ key: parameter.name,
52
+ value: parameterValue(parameter.schema, components),
53
+ ...parameter.required === true ? {} : { disabled: true }
54
+ }, parameter));
55
+ }
56
+ /**
57
+ * The Postman URL of an operation: `{id}` templates become `:id` path variables, query
58
+ * parameters become rows (optional ones disabled, so `raw` carries only the enabled ones).
59
+ */
60
+ function buildRequestUrl(path, parameters, components) {
61
+ const segments = path.split("/").filter((segment) => segment.length > 0).map((segment) => segment.replace(PATH_TEMPLATE_PARAM, ":$1"));
62
+ const variables = [...path.matchAll(PATH_TEMPLATE_PARAM)].flatMap((match) => {
63
+ const name = match[1];
64
+ if (name === void 0) return [];
65
+ const description = parameters.find((parameter) => parameter.in === "path" && parameter.name === name)?.description;
66
+ return [{
67
+ key: name,
68
+ value: "",
69
+ ...description ? { description } : {}
70
+ }];
71
+ });
72
+ const query = parameters.filter((parameter) => parameter.in === "query").flatMap((parameter) => queryRows(parameter, components));
73
+ const search = query.filter((row) => row.disabled !== true).map((row) => `${row.key}=${row.value}`).join("&");
74
+ return {
75
+ raw: `${BASE_URL_HOST}/${segments.join("/")}${search ? `?${search}` : ""}`,
76
+ host: [BASE_URL_HOST],
77
+ path: segments,
78
+ ...variables.length > 0 ? { variable: variables } : {},
79
+ ...query.length > 0 ? { query } : {}
80
+ };
81
+ }
82
+
83
+ //#endregion
84
+ export { buildHeaderParameters, buildRequestUrl };
85
+ //# sourceMappingURL=build-request-url.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-request-url.mjs","names":[],"sources":["../../../../../../../../core/src/openapi/postman/build-request-url.ts"],"sourcesContent":["import type { OpenApiParameter, OpenApiSchema } from \"../types\";\nimport { isRecord, resolveSchema, type SchemaComponents } from \"./schema-refs\";\nimport type { PostmanHeader, PostmanQueryParam, PostmanUrl, PostmanVariable } from \"./postman-types\";\n\n/** The Postman variable every request URL starts with. */\nexport const BASE_URL_HOST = \"{{baseUrl}}\";\n\nconst PATH_TEMPLATE_PARAM = /\\{([^}]+)\\}/g;\n\nfunction stringifyValue(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n\n return isRecord(value) || Array.isArray(value) ? JSON.stringify(value) : String(value);\n}\n\n/**\n * Value a parameter starts with in Postman: its declared `example`, `default`, `const` or\n * first `enum` value, otherwise empty so the caller fills it in.\n */\nfunction parameterValue(schema: OpenApiSchema, components: SchemaComponents): string {\n const resolved = resolveSchema(schema, components);\n\n for (const key of [\"example\", \"default\", \"const\"]) {\n if (key in resolved) {\n return stringifyValue(resolved[key]);\n }\n }\n\n if (Array.isArray(resolved.enum) && resolved.enum.length > 0) {\n return stringifyValue(resolved.enum[0]);\n }\n\n return \"\";\n}\n\nfunction withDescription<T extends object>(row: T, parameter: OpenApiParameter): T & { description?: string } {\n return parameter.description ? { ...row, description: parameter.description } : row;\n}\n\nfunction queryRows(parameter: OpenApiParameter, components: SchemaComponents): PostmanQueryParam[] {\n const disabled = parameter.required === true ? {} : { disabled: true as const };\n const schema = resolveSchema(parameter.schema, components);\n\n if (parameter.style === \"deepObject\" && isRecord(schema.properties)) {\n return Object.entries(schema.properties).map(([property, propertySchema]) => ({\n key: `${parameter.name}[${property}]`,\n value: isRecord(propertySchema) ? parameterValue(propertySchema, components) : \"\",\n ...disabled,\n }));\n }\n\n return [\n {\n key: parameter.name,\n value: parameterValue(parameter.schema, components),\n ...(parameter.description ? { description: parameter.description } : {}),\n ...disabled,\n },\n ];\n}\n\n/**\n * Header rows for the `header` parameters of an operation. Optional ones start disabled.\n */\nexport function buildHeaderParameters(\n parameters: readonly OpenApiParameter[],\n components: SchemaComponents,\n): PostmanHeader[] {\n return parameters\n .filter((parameter) => parameter.in === \"header\")\n .map((parameter) =>\n withDescription(\n {\n key: parameter.name,\n value: parameterValue(parameter.schema, components),\n ...(parameter.required === true ? {} : { disabled: true as const }),\n },\n parameter,\n ),\n );\n}\n\n/**\n * The Postman URL of an operation: `{id}` templates become `:id` path variables, query\n * parameters become rows (optional ones disabled, so `raw` carries only the enabled ones).\n */\nexport function buildRequestUrl(\n path: string,\n parameters: readonly OpenApiParameter[],\n components: SchemaComponents,\n): PostmanUrl {\n const segments = path\n .split(\"/\")\n .filter((segment) => segment.length > 0)\n .map((segment) => segment.replace(PATH_TEMPLATE_PARAM, \":$1\"));\n\n const variables: PostmanVariable[] = [...path.matchAll(PATH_TEMPLATE_PARAM)].flatMap((match) => {\n const name = match[1];\n\n if (name === undefined) {\n return [];\n }\n\n const description = parameters.find((parameter) => parameter.in === \"path\" && parameter.name === name)\n ?.description;\n\n return [{ key: name, value: \"\", ...(description ? { description } : {}) }];\n });\n\n const query = parameters\n .filter((parameter) => parameter.in === \"query\")\n .flatMap((parameter) => queryRows(parameter, components));\n\n const search = query\n .filter((row) => row.disabled !== true)\n .map((row) => `${row.key}=${row.value}`)\n .join(\"&\");\n\n return {\n raw: `${BASE_URL_HOST}/${segments.join(\"/\")}${search ? `?${search}` : \"\"}`,\n host: [BASE_URL_HOST],\n path: segments,\n ...(variables.length > 0 ? { variable: variables } : {}),\n ...(query.length > 0 ? { query } : {}),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { exampleFromSchema } from "./example-from-schema.mjs";
2
+ import { httpStatusText } from "./http-status-text.mjs";
3
+
4
+ //#region ../core/src/openapi/postman/build-saved-responses.ts
5
+ function previewLanguage(contentType) {
6
+ if (contentType === "application/json" || contentType.endsWith("+json")) return "json";
7
+ return contentType === "text/html" ? "html" : "text";
8
+ }
9
+ function stringExample(example) {
10
+ return typeof example === "string" ? example : "";
11
+ }
12
+ function responseBody(content, components) {
13
+ const contentTypes = Object.keys(content);
14
+ const contentType = contentTypes.find((type) => previewLanguage(type) === "json") ?? contentTypes[0];
15
+ const schema = contentType !== void 0 ? content[contentType]?.schema : void 0;
16
+ if (contentType === void 0 || schema === void 0) return {
17
+ body: "",
18
+ header: [],
19
+ language: "text"
20
+ };
21
+ const language = previewLanguage(contentType);
22
+ const example = exampleFromSchema(schema, components);
23
+ return {
24
+ body: language === "json" ? JSON.stringify(example, null, 2) : stringExample(example),
25
+ header: [{
26
+ key: "Content-Type",
27
+ value: contentType,
28
+ type: "text"
29
+ }],
30
+ language
31
+ };
32
+ }
33
+ /**
34
+ * One saved Postman response per declared numeric status, with an example body from the
35
+ * response schema. `default` and range keys (`2XX`) have no single status code and are skipped.
36
+ */
37
+ function buildSavedResponses(responses, originalRequest, components) {
38
+ return Object.entries(responses).flatMap(([status, response]) => {
39
+ if (!/^\d{3}$/.test(status)) return [];
40
+ const code = Number(status);
41
+ const { body, header, language } = response.content ? responseBody(response.content, components) : {
42
+ body: "",
43
+ header: [],
44
+ language: "text"
45
+ };
46
+ return [{
47
+ name: `${status} ${response.description}`,
48
+ originalRequest,
49
+ status: httpStatusText(code, response.description),
50
+ code,
51
+ _postman_previewlanguage: language,
52
+ header,
53
+ body
54
+ }];
55
+ });
56
+ }
57
+
58
+ //#endregion
59
+ export { buildSavedResponses };
60
+ //# sourceMappingURL=build-saved-responses.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-saved-responses.mjs","names":[],"sources":["../../../../../../../../core/src/openapi/postman/build-saved-responses.ts"],"sourcesContent":["import type { OpenApiOperation } from \"../types\";\nimport { exampleFromSchema } from \"./example-from-schema\";\nimport { httpStatusText } from \"./http-status-text\";\nimport type { PostmanHeader, PostmanOriginalRequest, PostmanResponse } from \"./postman-types\";\nimport type { SchemaComponents } from \"./schema-refs\";\n\ntype PreviewLanguage = PostmanResponse[\"_postman_previewlanguage\"];\n\nfunction previewLanguage(contentType: string): PreviewLanguage {\n if (contentType === \"application/json\" || contentType.endsWith(\"+json\")) {\n return \"json\";\n }\n\n return contentType === \"text/html\" ? \"html\" : \"text\";\n}\n\nfunction stringExample(example: unknown): string {\n return typeof example === \"string\" ? example : \"\";\n}\n\nfunction responseBody(\n content: NonNullable<OpenApiOperation[\"responses\"][string][\"content\"]>,\n components: SchemaComponents,\n): { body: string; header: PostmanHeader[]; language: PreviewLanguage } {\n const contentTypes = Object.keys(content);\n const contentType = contentTypes.find((type) => previewLanguage(type) === \"json\") ?? contentTypes[0];\n const schema = contentType !== undefined ? content[contentType]?.schema : undefined;\n\n if (contentType === undefined || schema === undefined) {\n return { body: \"\", header: [], language: \"text\" };\n }\n\n const language = previewLanguage(contentType);\n const example = exampleFromSchema(schema, components);\n const body = language === \"json\" ? JSON.stringify(example, null, 2) : stringExample(example);\n\n return { body, header: [{ key: \"Content-Type\", value: contentType, type: \"text\" }], language };\n}\n\n/**\n * One saved Postman response per declared numeric status, with an example body from the\n * response schema. `default` and range keys (`2XX`) have no single status code and are skipped.\n */\nexport function buildSavedResponses(\n responses: OpenApiOperation[\"responses\"],\n originalRequest: PostmanOriginalRequest,\n components: SchemaComponents,\n): PostmanResponse[] {\n return Object.entries(responses).flatMap(([status, response]): PostmanResponse[] => {\n if (!/^\\d{3}$/.test(status)) {\n return [];\n }\n\n const code = Number(status);\n const { body, header, language } = response.content\n ? responseBody(response.content, components)\n : { body: \"\", header: [], language: \"text\" as const };\n\n return [\n {\n name: `${status} ${response.description}`,\n originalRequest,\n status: httpStatusText(code, response.description),\n code,\n _postman_previewlanguage: language,\n header,\n body,\n },\n ];\n });\n}\n"],"mappings":";;;;AAQA,SAAS,gBAAgB,aAAsC;CAC7D,IAAI,gBAAgB,sBAAsB,YAAY,SAAS,OAAO,GACpE,OAAO;CAGT,OAAO,gBAAgB,cAAc,SAAS;AAChD;AAEA,SAAS,cAAc,SAA0B;CAC/C,OAAO,OAAO,YAAY,WAAW,UAAU;AACjD;AAEA,SAAS,aACP,SACA,YACsE;CACtE,MAAM,eAAe,OAAO,KAAK,OAAO;CACxC,MAAM,cAAc,aAAa,MAAM,SAAS,gBAAgB,IAAI,MAAM,MAAM,KAAK,aAAa;CAClG,MAAM,SAAS,gBAAgB,SAAY,QAAQ,YAAY,EAAE,SAAS;CAE1E,IAAI,gBAAgB,UAAa,WAAW,QAC1C,OAAO;EAAE,MAAM;EAAI,QAAQ,CAAC;EAAG,UAAU;CAAO;CAGlD,MAAM,WAAW,gBAAgB,WAAW;CAC5C,MAAM,UAAU,kBAAkB,QAAQ,UAAU;CAGpD,OAAO;EAAE,MAFI,aAAa,SAAS,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI,cAAc,OAAO;EAE5E,QAAQ,CAAC;GAAE,KAAK;GAAgB,OAAO;GAAa,MAAM;EAAO,CAAC;EAAG;CAAS;AAC/F;;;;;AAMA,SAAgB,oBACd,WACA,iBACA,YACmB;CACnB,OAAO,OAAO,QAAQ,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,cAAiC;EAClF,IAAI,CAAC,UAAU,KAAK,MAAM,GACxB,OAAO,CAAC;EAGV,MAAM,OAAO,OAAO,MAAM;EAC1B,MAAM,EAAE,MAAM,QAAQ,aAAa,SAAS,UACxC,aAAa,SAAS,SAAS,UAAU,IACzC;GAAE,MAAM;GAAI,QAAQ,CAAC;GAAG,UAAU;EAAgB;EAEtD,OAAO,CACL;GACE,MAAM,GAAG,OAAO,GAAG,SAAS;GAC5B;GACA,QAAQ,eAAe,MAAM,SAAS,WAAW;GACjD;GACA,0BAA0B;GAC1B;GACA;EACF,CACF;CACF,CAAC;AACH"}
@@ -0,0 +1,17 @@
1
+ import { OpenApiSchema } from "../types.mjs";
2
+ import { SchemaComponents } from "./schema-refs.mjs";
3
+
4
+ //#region ../core/src/openapi/postman/example-from-schema.d.ts
5
+ /**
6
+ * A deterministic example value for a JSON Schema.
7
+ *
8
+ * Explicit `example`, `const`, `default`, `enum[0]` and `examples[0]` win, in that order;
9
+ * otherwise a type sample is produced (format-aware strings, `0`, `false`, one array item,
10
+ * every object property). `$ref`s resolve against `components`; a cyclic reference is cut
11
+ * (the property is omitted, an array of it is empty). A nullable union yields its non-null
12
+ * branch. A schema with no usable type is `null`.
13
+ */
14
+ declare function exampleFromSchema(schema: OpenApiSchema, components?: SchemaComponents): unknown;
15
+ //#endregion
16
+ export { exampleFromSchema };
17
+ //# sourceMappingURL=example-from-schema.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"example-from-schema.d.mts","names":[],"sources":["../../../../../../../../core/src/openapi/postman/example-from-schema.ts"],"mappings":";;;;;;AAgJA;;;;;;;iBAAgB,iBAAA,CAAkB,MAAA,EAAQ,aAAA,EAAe,UAAA,GAAa,gBAAgB"}
@@ -0,0 +1,92 @@
1
+ import { isRecord, primaryType, refName, resolveSchema } from "./schema-refs.mjs";
2
+
3
+ //#region ../core/src/openapi/postman/example-from-schema.ts
4
+ const STRING_FORMAT_EXAMPLES = {
5
+ email: "user@example.com",
6
+ "date-time": "2024-01-01T00:00:00.000Z",
7
+ date: "2024-01-01",
8
+ time: "00:00:00",
9
+ uri: "https://example.com",
10
+ url: "https://example.com",
11
+ iri: "https://example.com",
12
+ uuid: "00000000-0000-4000-8000-000000000000",
13
+ hostname: "example.com",
14
+ ipv4: "127.0.0.1",
15
+ ipv6: "::1"
16
+ };
17
+ function numberExample(schema) {
18
+ if (typeof schema.minimum === "number" && schema.minimum > 0) return schema.minimum;
19
+ if (typeof schema.maximum === "number" && schema.maximum < 0) return schema.maximum;
20
+ return 0;
21
+ }
22
+ function stringExample(schema) {
23
+ const format = typeof schema.format === "string" ? schema.format : void 0;
24
+ return (format !== void 0 ? STRING_FORMAT_EXAMPLES[format] : void 0) ?? "string";
25
+ }
26
+ function isNullBranch(branch, components) {
27
+ return isRecord(branch) && primaryType(resolveSchema(branch, components)) === "null";
28
+ }
29
+ function mergeExamples(parts) {
30
+ const objects = parts.filter(isRecord);
31
+ if (objects.length === parts.length) return Object.assign({}, ...objects);
32
+ return parts[parts.length - 1] ?? null;
33
+ }
34
+ /**
35
+ * `undefined` marks a `$ref` cycle: the caller omits the property, or yields an empty array.
36
+ */
37
+ function generate(schema, components, stack) {
38
+ if (!isRecord(schema)) return null;
39
+ const name = refName(schema);
40
+ if (name !== void 0) {
41
+ const target = components?.[name];
42
+ if (stack.includes(name)) return;
43
+ return target ? generate(target, components, [...stack, name]) : null;
44
+ }
45
+ if ("example" in schema) return schema.example;
46
+ if ("const" in schema) return schema.const;
47
+ if ("default" in schema) return schema.default;
48
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) return schema.enum[0];
49
+ if (Array.isArray(schema.examples) && schema.examples.length > 0) return schema.examples[0];
50
+ for (const key of ["oneOf", "anyOf"]) {
51
+ const branches = schema[key];
52
+ if (Array.isArray(branches) && branches.length > 0) return generate(branches.find((candidate) => !isNullBranch(candidate, components)) ?? branches[0], components, stack);
53
+ }
54
+ if (Array.isArray(schema.allOf) && schema.allOf.length > 0) return mergeExamples(schema.allOf.map((part) => generate(part, components, stack)));
55
+ switch (primaryType(schema)) {
56
+ case "string": return stringExample(schema);
57
+ case "number":
58
+ case "integer": return numberExample(schema);
59
+ case "boolean": return false;
60
+ case "array": {
61
+ const item = generate(schema.items, components, stack);
62
+ return item === void 0 ? [] : [item];
63
+ }
64
+ case "object": {
65
+ const result = {};
66
+ const properties = isRecord(schema.properties) ? schema.properties : {};
67
+ for (const [key, property] of Object.entries(properties)) {
68
+ const value = generate(property, components, stack);
69
+ if (value !== void 0) result[key] = value;
70
+ }
71
+ return result;
72
+ }
73
+ default: return null;
74
+ }
75
+ }
76
+ /**
77
+ * A deterministic example value for a JSON Schema.
78
+ *
79
+ * Explicit `example`, `const`, `default`, `enum[0]` and `examples[0]` win, in that order;
80
+ * otherwise a type sample is produced (format-aware strings, `0`, `false`, one array item,
81
+ * every object property). `$ref`s resolve against `components`; a cyclic reference is cut
82
+ * (the property is omitted, an array of it is empty). A nullable union yields its non-null
83
+ * branch. A schema with no usable type is `null`.
84
+ */
85
+ function exampleFromSchema(schema, components) {
86
+ const value = generate(schema, components, []);
87
+ return value === void 0 ? null : value;
88
+ }
89
+
90
+ //#endregion
91
+ export { exampleFromSchema };
92
+ //# sourceMappingURL=example-from-schema.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"example-from-schema.mjs","names":[],"sources":["../../../../../../../../core/src/openapi/postman/example-from-schema.ts"],"sourcesContent":["import type { OpenApiSchema } from \"../types\";\nimport { isRecord, primaryType, refName, resolveSchema, type SchemaComponents } from \"./schema-refs\";\n\nconst STRING_FORMAT_EXAMPLES: Record<string, string> = {\n email: \"user@example.com\",\n \"date-time\": \"2024-01-01T00:00:00.000Z\",\n date: \"2024-01-01\",\n time: \"00:00:00\",\n uri: \"https://example.com\",\n url: \"https://example.com\",\n iri: \"https://example.com\",\n uuid: \"00000000-0000-4000-8000-000000000000\",\n hostname: \"example.com\",\n ipv4: \"127.0.0.1\",\n ipv6: \"::1\",\n};\n\nfunction numberExample(schema: OpenApiSchema): number {\n if (typeof schema.minimum === \"number\" && schema.minimum > 0) {\n return schema.minimum;\n }\n\n if (typeof schema.maximum === \"number\" && schema.maximum < 0) {\n return schema.maximum;\n }\n\n return 0;\n}\n\nfunction stringExample(schema: OpenApiSchema): string {\n const format = typeof schema.format === \"string\" ? schema.format : undefined;\n\n return (format !== undefined ? STRING_FORMAT_EXAMPLES[format] : undefined) ?? \"string\";\n}\n\nfunction isNullBranch(branch: unknown, components: SchemaComponents): boolean {\n return isRecord(branch) && primaryType(resolveSchema(branch, components)) === \"null\";\n}\n\nfunction mergeExamples(parts: unknown[]): unknown {\n const objects = parts.filter(isRecord);\n\n if (objects.length === parts.length) {\n return Object.assign({}, ...objects);\n }\n\n return parts[parts.length - 1] ?? null;\n}\n\n/**\n * `undefined` marks a `$ref` cycle: the caller omits the property, or yields an empty array.\n */\nfunction generate(schema: unknown, components: SchemaComponents, stack: readonly string[]): unknown {\n if (!isRecord(schema)) {\n return null;\n }\n\n const name = refName(schema);\n\n if (name !== undefined) {\n const target = components?.[name];\n\n if (stack.includes(name)) {\n return undefined;\n }\n\n return target ? generate(target, components, [...stack, name]) : null;\n }\n\n if (\"example\" in schema) {\n return schema.example;\n }\n\n if (\"const\" in schema) {\n return schema.const;\n }\n\n if (\"default\" in schema) {\n return schema.default;\n }\n\n if (Array.isArray(schema.enum) && schema.enum.length > 0) {\n return schema.enum[0];\n }\n\n if (Array.isArray(schema.examples) && schema.examples.length > 0) {\n return schema.examples[0];\n }\n\n for (const key of [\"oneOf\", \"anyOf\"] as const) {\n const branches = schema[key];\n\n if (Array.isArray(branches) && branches.length > 0) {\n const branch = branches.find((candidate) => !isNullBranch(candidate, components)) ?? branches[0];\n\n return generate(branch, components, stack);\n }\n }\n\n if (Array.isArray(schema.allOf) && schema.allOf.length > 0) {\n return mergeExamples(schema.allOf.map((part) => generate(part, components, stack)));\n }\n\n switch (primaryType(schema)) {\n case \"string\":\n return stringExample(schema);\n case \"number\":\n case \"integer\":\n return numberExample(schema);\n case \"boolean\":\n return false;\n case \"array\": {\n const item = generate(schema.items, components, stack);\n\n return item === undefined ? [] : [item];\n }\n case \"object\": {\n const result: Record<string, unknown> = {};\n const properties = isRecord(schema.properties) ? schema.properties : {};\n\n for (const [key, property] of Object.entries(properties)) {\n const value = generate(property, components, stack);\n\n if (value !== undefined) {\n result[key] = value;\n }\n }\n\n return result;\n }\n default:\n return null;\n }\n}\n\n/**\n * A deterministic example value for a JSON Schema.\n *\n * Explicit `example`, `const`, `default`, `enum[0]` and `examples[0]` win, in that order;\n * otherwise a type sample is produced (format-aware strings, `0`, `false`, one array item,\n * every object property). `$ref`s resolve against `components`; a cyclic reference is cut\n * (the property is omitted, an array of it is empty). A nullable union yields its non-null\n * branch. A schema with no usable type is `null`.\n */\nexport function exampleFromSchema(schema: OpenApiSchema, components?: SchemaComponents): unknown {\n const value = generate(schema, components, []);\n\n return value === undefined ? null : value;\n}\n"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ //#region ../core/src/openapi/postman/http-status-text.ts
2
+ const STATUS_TEXT = {
3
+ 200: "OK",
4
+ 201: "Created",
5
+ 202: "Accepted",
6
+ 204: "No Content",
7
+ 301: "Moved Permanently",
8
+ 302: "Found",
9
+ 304: "Not Modified",
10
+ 400: "Bad Request",
11
+ 401: "Unauthorized",
12
+ 403: "Forbidden",
13
+ 404: "Not Found",
14
+ 405: "Method Not Allowed",
15
+ 409: "Conflict",
16
+ 410: "Gone",
17
+ 422: "Unprocessable Entity",
18
+ 429: "Too Many Requests",
19
+ 500: "Internal Server Error",
20
+ 503: "Service Unavailable"
21
+ };
22
+ /**
23
+ * The HTTP reason phrase of a status code, or `fallback` for one that is not listed.
24
+ */
25
+ function httpStatusText(code, fallback) {
26
+ return STATUS_TEXT[code] ?? fallback;
27
+ }
28
+
29
+ //#endregion
30
+ export { httpStatusText };
31
+ //# sourceMappingURL=http-status-text.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-status-text.mjs","names":[],"sources":["../../../../../../../../core/src/openapi/postman/http-status-text.ts"],"sourcesContent":["const STATUS_TEXT: Record<number, string> = {\n 200: \"OK\",\n 201: \"Created\",\n 202: \"Accepted\",\n 204: \"No Content\",\n 301: \"Moved Permanently\",\n 302: \"Found\",\n 304: \"Not Modified\",\n 400: \"Bad Request\",\n 401: \"Unauthorized\",\n 403: \"Forbidden\",\n 404: \"Not Found\",\n 405: \"Method Not Allowed\",\n 409: \"Conflict\",\n 410: \"Gone\",\n 422: \"Unprocessable Entity\",\n 429: \"Too Many Requests\",\n 500: \"Internal Server Error\",\n 503: \"Service Unavailable\",\n};\n\n/**\n * The HTTP reason phrase of a status code, or `fallback` for one that is not listed.\n */\nexport function httpStatusText(code: number, fallback: string): string {\n return STATUS_TEXT[code] ?? fallback;\n}\n"],"mappings":";AAAA,MAAM,cAAsC;CAC1C,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;AACP;;;;AAKA,SAAgB,eAAe,MAAc,UAA0B;CACrE,OAAO,YAAY,SAAS;AAC9B"}
@@ -0,0 +1,3 @@
1
+ import { PostmanAuth, PostmanAuthEntry, PostmanBody, PostmanCollection, PostmanCollectionOptions, PostmanFolder, PostmanFormParam, PostmanHeader, PostmanItem, PostmanOriginalRequest, PostmanQueryParam, PostmanRequest, PostmanRequestItem, PostmanResponse, PostmanUrl, PostmanVariable } from "./postman-types.mjs";
2
+ import { exampleFromSchema } from "./example-from-schema.mjs";
3
+ import { DEFAULT_POSTMAN_BASE_URL, POSTMAN_COLLECTION_SCHEMA, openApiToPostmanCollection } from "./openapi-to-postman-collection.mjs";
@@ -0,0 +1,22 @@
1
+ import { PostmanCollection, PostmanCollectionOptions } from "./postman-types.mjs";
2
+ import { OpenApiDocument } from "../types.mjs";
3
+
4
+ //#region ../core/src/openapi/postman/openapi-to-postman-collection.d.ts
5
+ /** `info.schema` of every collection this converter produces. */
6
+ declare const POSTMAN_COLLECTION_SCHEMA = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json";
7
+ /** `{{baseUrl}}` when neither the options nor the document name a server. */
8
+ declare const DEFAULT_POSTMAN_BASE_URL = "http://localhost:3000";
9
+ /**
10
+ * Convert an OpenAPI document into a Postman Collection v2.1.0 object.
11
+ *
12
+ * Pure and deterministic (the collection id is a UUIDv5 of the title), derived only from the
13
+ * document so the collection can never disagree with the OpenAPI output. Each tag becomes a
14
+ * folder in order of first appearance and untagged operations stay at the root; each
15
+ * operation becomes a request with example bodies generated from its schemas and a saved
16
+ * response per declared status. `{{baseUrl}}` and `{{token}}` are collection variables; a
17
+ * bearer scheme becomes collection-level bearer auth and public operations opt out of it.
18
+ */
19
+ declare function openApiToPostmanCollection(document: OpenApiDocument, options?: PostmanCollectionOptions): PostmanCollection;
20
+ //#endregion
21
+ export { DEFAULT_POSTMAN_BASE_URL, POSTMAN_COLLECTION_SCHEMA, openApiToPostmanCollection };
22
+ //# sourceMappingURL=openapi-to-postman-collection.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi-to-postman-collection.d.mts","names":[],"sources":["../../../../../../../../core/src/openapi/postman/openapi-to-postman-collection.ts"],"mappings":";;;;;cAgBa,yBAAA;AAAb;AAAA,cAGa,wBAAA;;;AAHyB;AAGtC;;;;AAAqC;AAqDrC;;iBAAgB,0BAAA,CACd,QAAA,EAAU,eAAA,EACV,OAAA,GAAS,wBAAA,GACR,iBAAA"}