@sdk-it/spec 0.25.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +2 -2
- package/dist/lib/create-operation.d.ts +28 -0
- package/dist/lib/create-operation.d.ts.map +1 -0
- package/dist/lib/create-operation.js +62 -0
- package/dist/lib/create-operation.js.map +7 -0
- package/dist/lib/for-each-operation.d.ts.map +1 -1
- package/dist/lib/for-each-operation.js +0 -3
- package/dist/lib/for-each-operation.js.map +2 -2
- package/dist/lib/guess/guess-resource.d.ts +7 -0
- package/dist/lib/guess/guess-resource.d.ts.map +1 -0
- package/dist/lib/guess/guess-resource.js +76 -0
- package/dist/lib/guess/guess-resource.js.map +7 -0
- package/dist/lib/metadata.test.js +359 -0
- package/dist/lib/metadata.test.js.map +7 -0
- package/dist/lib/operation.d.ts +1 -32
- package/dist/lib/operation.d.ts.map +1 -1
- package/dist/lib/operation.js +32 -312
- package/dist/lib/operation.js.map +2 -2
- package/dist/lib/options.d.ts +42 -1
- package/dist/lib/options.d.ts.map +1 -1
- package/dist/lib/options.js +23 -8
- package/dist/lib/options.js.map +2 -2
- package/dist/lib/pagination/guess-pagination.d.ts +50 -0
- package/dist/lib/pagination/guess-pagination.d.ts.map +1 -0
- package/dist/lib/pagination/guess-pagination.js +222 -0
- package/dist/lib/pagination/guess-pagination.js.map +7 -0
- package/dist/lib/pagination/pagination.d.ts +2 -49
- package/dist/lib/pagination/pagination.d.ts.map +1 -1
- package/dist/lib/pagination/pagination.js +43 -209
- package/dist/lib/pagination/pagination.js.map +2 -2
- package/dist/lib/pagination/pagination.test.js +2 -1
- package/dist/lib/pagination/pagination.test.js.map +2 -2
- package/dist/lib/sidebar.d.ts +4 -23
- package/dist/lib/sidebar.d.ts.map +1 -1
- package/dist/lib/sidebar.js +22 -65
- package/dist/lib/sidebar.js.map +3 -3
- package/dist/lib/tune-request-body.d.ts +5 -0
- package/dist/lib/tune-request-body.d.ts.map +1 -0
- package/dist/lib/tune-request-body.js +88 -0
- package/dist/lib/tune-request-body.js.map +7 -0
- package/dist/lib/tune-response.d.ts +5 -0
- package/dist/lib/tune-response.d.ts.map +1 -0
- package/dist/lib/tune-response.js +102 -0
- package/dist/lib/tune-response.js.map +7 -0
- package/dist/lib/types.d.ts +8 -3
- package/dist/lib/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/pagination/pagination.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n
|
|
5
|
-
"mappings": "AAMA,SAAS,aAAa;
|
|
4
|
+
"sourcesContent": ["import type {\n RequestBodyObject,\n ResponseObject,\n SchemaObject,\n} from 'openapi3-ts/oas31';\n\nimport { followRef, isRef } from '@sdk-it/core/ref.js';\n\nimport type { OurOpenAPIObject, TunedOperationObject } from '../types.js';\nimport { guessPagination } from './guess-pagination.js';\n\nexport function toPagination(\n spec: OurOpenAPIObject,\n tunedOperation: TunedOperationObject,\n) {\n if (tunedOperation['x-pagination']) {\n return tunedOperation['x-pagination'];\n }\n const schema = getResponseContentSchema(\n spec,\n tunedOperation.responses['200'],\n 'application/json',\n );\n const pagination = guessPagination(\n tunedOperation,\n tunedOperation.requestBody\n ? getRequestContentSchema(\n spec,\n tunedOperation.requestBody,\n 'application/json',\n )\n : undefined,\n schema,\n );\n if (pagination && pagination.type !== 'none' && schema) {\n return pagination;\n }\n return undefined;\n}\n\nfunction getResponseContentSchema(\n spec: OurOpenAPIObject,\n response: ResponseObject,\n type: string,\n) {\n if (!response) {\n return undefined;\n }\n const content = response.content;\n if (!content) {\n return undefined;\n }\n for (const contentType in content) {\n if (contentType.toLowerCase() === type.toLowerCase()) {\n return isRef(content[contentType].schema)\n ? followRef<SchemaObject>(spec, content[contentType].schema.$ref)\n : content[contentType].schema;\n }\n }\n return undefined;\n}\n\nfunction getRequestContentSchema(\n spec: OurOpenAPIObject,\n requestBody: RequestBodyObject,\n type: string,\n) {\n const content = requestBody.content;\n if (!content) {\n return undefined;\n }\n for (const contentType in content) {\n if (contentType.toLowerCase() === type.toLowerCase()) {\n return isRef(content[contentType].schema)\n ? followRef<SchemaObject>(spec, content[contentType].schema.$ref)\n : content[contentType].schema;\n }\n }\n return undefined;\n}\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,WAAW,aAAa;AAGjC,SAAS,uBAAuB;AAEzB,SAAS,aACd,MACA,gBACA;AACA,MAAI,eAAe,cAAc,GAAG;AAClC,WAAO,eAAe,cAAc;AAAA,EACtC;AACA,QAAM,SAAS;AAAA,IACb;AAAA,IACA,eAAe,UAAU,KAAK;AAAA,IAC9B;AAAA,EACF;AACA,QAAM,aAAa;AAAA,IACjB;AAAA,IACA,eAAe,cACX;AAAA,MACE;AAAA,MACA,eAAe;AAAA,MACf;AAAA,IACF,IACA;AAAA,IACJ;AAAA,EACF;AACA,MAAI,cAAc,WAAW,SAAS,UAAU,QAAQ;AACtD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,yBACP,MACA,UACA,MACA;AACA,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AACA,QAAM,UAAU,SAAS;AACzB,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,aAAW,eAAe,SAAS;AACjC,QAAI,YAAY,YAAY,MAAM,KAAK,YAAY,GAAG;AACpD,aAAO,MAAM,QAAQ,WAAW,EAAE,MAAM,IACpC,UAAwB,MAAM,QAAQ,WAAW,EAAE,OAAO,IAAI,IAC9D,QAAQ,WAAW,EAAE;AAAA,IAC3B;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,wBACP,MACA,aACA,MACA;AACA,QAAM,UAAU,YAAY;AAC5B,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,aAAW,eAAe,SAAS;AACjC,QAAI,YAAY,YAAY,MAAM,KAAK,YAAY,GAAG;AACpD,aAAO,MAAM,QAAQ,WAAW,EAAE,MAAM,IACpC,UAAwB,MAAM,QAAQ,WAAW,EAAE,OAAO,IAAI,IAC9D,QAAQ,WAAW,EAAE;AAAA,IAC3B;AAAA,EACF;AACA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,9 +8,10 @@ import {
|
|
|
8
8
|
PAGE_NUMBER_REGEXES,
|
|
9
9
|
PAGE_SIZE_REGEXES,
|
|
10
10
|
guessPagination
|
|
11
|
-
} from "./pagination.ts";
|
|
11
|
+
} from "./guess-pagination.ts";
|
|
12
12
|
function createOperation(params) {
|
|
13
13
|
return {
|
|
14
|
+
"x-fn-name": "testFunction",
|
|
14
15
|
tags: ["test"],
|
|
15
16
|
operationId: "testOperation",
|
|
16
17
|
parameters: params,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/pagination/pagination.test.ts"],
|
|
4
|
-
"sourcesContent": ["import assert from 'node:assert/strict';\nimport { describe, test } from 'node:test';\nimport type { ParameterObject } from 'openapi3-ts/oas31';\n\nimport type { TunedOperationObject } from '../types.ts';\nimport {\n CURSOR_LIMIT_REGEXES,\n CURSOR_REGEXES,\n GENERIC_LIMIT_PARAM_REGEXES,\n OFFSET_PARAM_REGEXES,\n PAGE_NUMBER_REGEXES,\n PAGE_SIZE_REGEXES,\n guessPagination,\n} from './pagination.ts';\n\nfunction createOperation(params: ParameterObject[]): TunedOperationObject {\n return {\n tags: ['test'],\n operationId: 'testOperation',\n parameters: params,\n requestBody: { content: {} },\n responses: {},\n };\n}\n\nfunction qParam(name: string): ParameterObject {\n return {\n name,\n in: 'query',\n required: false,\n schema: {\n type: 'string',\n },\n };\n}\n\nfunction hParam(name: string): ParameterObject {\n return {\n name,\n in: 'header',\n required: false,\n schema: {\n type: 'string',\n },\n };\n}\nfunction pParam(name: string): ParameterObject {\n return {\n name,\n in: 'path',\n required: false,\n schema: {\n type: 'string',\n },\n };\n}\nfunction getExpectedKeyword(paramName: string, regexArray: RegExp[]): string {\n for (const regex of regexArray) {\n const match = paramName.match(regex);\n if (match) {\n return match[0];\n }\n }\n // This might return undefined if the paramName is not expected to match any regex in the array,\n // which is fine for negative test cases or if the mock doesn't perfectly align.\n // For positive cases, ensure your actual implementation and regexes would provide a match.\n return paramName; // Fallback for mock simplicity, real tests need accurate keyword\n}\n\ndescribe('guessPagination()', () => {\n describe('No Pagination Detected', () => {\n test('should return \"none\" for an operation with an empty parameters array', () => {\n const op = createOperation([]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should return \"none\" for an operation with undefined parameters', () => {\n const op = createOperation(undefined as never);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should return \"none\" for non-pagination query parameters', () => {\n const op = createOperation([qParam('search'), qParam('filterBy')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should return \"none\" if relevant parameters are not in \"query\"', () => {\n const op = createOperation([hParam('offset'), hParam('limit')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should return \"none\" if only one part of a pair is present (e.g., only offset)', () => {\n assert.deepStrictEqual(\n guessPagination(createOperation([qParam('offset')])),\n { type: 'none' },\n 'Only offset',\n );\n assert.deepStrictEqual(\n guessPagination(createOperation([qParam('page')])),\n { type: 'none' },\n 'Only page',\n );\n assert.deepStrictEqual(\n guessPagination(createOperation([qParam('cursor')])),\n { type: 'none' },\n 'Only cursor',\n );\n assert.deepStrictEqual(\n guessPagination(createOperation([qParam('limit')])),\n { type: 'none' },\n 'Only limit',\n );\n });\n\n test('should return \"none\" for mixed non-query and insufficient query params', () => {\n const op = createOperation([\n pParam('userId'),\n qParam('offset'),\n hParam('X-Request-ID'),\n ]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n });\n\n describe('Offset Pagination Detection', () => {\n const testOffsetKeywords = [\n 'offset',\n 'skip',\n 'start',\n 'start_index',\n 'starting_at',\n 'from',\n 'Offset',\n 'SKIP',\n ];\n const testLimitKeywords = [\n 'limit',\n 'count',\n 'size',\n 'page_size',\n 'pageSize',\n 'max_results',\n 'take',\n 'Limit',\n 'COUNT',\n ];\n\n for (const offsetKey of testOffsetKeywords) {\n for (const limitKey of testLimitKeywords) {\n if (offsetKey.toLowerCase() === limitKey.toLowerCase()) continue;\n\n test(`should detect offset with \"${offsetKey}\" and \"${limitKey}\"`, () => {\n const op = createOperation([qParam(offsetKey), qParam(limitKey)]);\n const result = guessPagination(op);\n // Note: With a simple mock, these detailed assertions might fail.\n // They are designed for the actual implementation.\n assert.strictEqual(\n result.type,\n 'offset',\n `Failed for ${offsetKey}, ${limitKey}`,\n );\n assert.strictEqual(result.offsetParamName, offsetKey);\n assert.strictEqual(\n result.offsetKeyword,\n getExpectedKeyword(offsetKey, OFFSET_PARAM_REGEXES),\n );\n assert.strictEqual(result.limitParamName, limitKey);\n assert.strictEqual(\n result.limitKeyword,\n getExpectedKeyword(limitKey, GENERIC_LIMIT_PARAM_REGEXES),\n );\n });\n }\n }\n\n test('should not detect offset if one param is not in query', () => {\n const op = createOperation([hParam('offset'), qParam('limit')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should not detect with two offset-like params and no limit', () => {\n const op = createOperation([qParam('offset'), qParam('skip')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should correctly handle params in different order', () => {\n const op = createOperation([qParam('limit'), qParam('offset')]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'offset');\n assert.strictEqual(result.offsetParamName, 'offset');\n assert.strictEqual(result.limitParamName, 'limit');\n });\n\n test('should handle extra non-pagination params', () => {\n const op = createOperation([\n qParam('filter'),\n qParam('offset'),\n qParam('sort'),\n qParam('limit'),\n ]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'offset');\n assert.strictEqual(result.offsetParamName, 'offset');\n assert.strictEqual(result.limitParamName, 'limit');\n });\n });\n\n describe('Page Pagination Detection', () => {\n const testPageNumKeywords = [\n 'page',\n 'p',\n 'page_number',\n 'pageNum',\n 'page_idx',\n 'Page',\n 'P',\n ];\n const testPageSizeKeywords = [\n 'page_size',\n 'pageSize',\n 'size',\n 'limit',\n 'count',\n 'per_page',\n 'per-page',\n 'num_items',\n 'Size',\n 'LIMIT',\n ];\n\n for (const pageKey of testPageNumKeywords) {\n for (const sizeKey of testPageSizeKeywords) {\n if (pageKey.toLowerCase() === sizeKey.toLowerCase()) continue;\n\n test(`should detect page with \"${pageKey}\" and \"${sizeKey}\"`, () => {\n const op = createOperation([qParam(pageKey), qParam(sizeKey)]);\n const result = guessPagination(op);\n assert.strictEqual(\n result.type,\n 'page',\n `Failed for ${pageKey}, ${sizeKey}`,\n );\n assert.strictEqual(result.pageNumberParamName, pageKey);\n assert.strictEqual(\n result.pageNumberKeyword,\n getExpectedKeyword(pageKey, PAGE_NUMBER_REGEXES),\n );\n assert.strictEqual(result.pageSizeParamName, sizeKey);\n assert.strictEqual(\n result.pageSizeKeyword,\n getExpectedKeyword(sizeKey, PAGE_SIZE_REGEXES),\n );\n });\n }\n }\n test('should not detect page if one param is not in query', () => {\n const op = createOperation([hParam('page'), qParam('size')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should not detect with two page-number-like params and no size', () => {\n const op = createOperation([qParam('page'), qParam('page_number')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n });\n\n describe('Cursor Pagination Detection', () => {\n const testCursorKeywords = [\n 'cursor',\n 'after',\n 'before_cursor',\n 'next_page_token',\n 'pageToken',\n 'continuation_token',\n 'Cursor',\n 'AFTER',\n ];\n const testCursorLimitKeywords = [\n 'limit',\n 'count',\n 'size',\n 'first',\n 'last',\n 'page_size',\n 'num_items',\n 'take',\n 'First',\n 'LAST',\n ];\n\n for (const cursorKey of testCursorKeywords) {\n for (const limitKey of testCursorLimitKeywords) {\n if (cursorKey.toLowerCase() === limitKey.toLowerCase()) continue;\n\n test(`should detect cursor with \"${cursorKey}\" and \"${limitKey}\"`, () => {\n const op = createOperation([qParam(cursorKey), qParam(limitKey)]);\n const result = guessPagination(op);\n assert.strictEqual(\n result.type,\n 'cursor',\n `Failed for ${cursorKey}, ${limitKey}`,\n );\n assert.strictEqual(result.cursorParamName, cursorKey);\n assert.strictEqual(\n result.cursorKeyword,\n getExpectedKeyword(cursorKey, CURSOR_REGEXES),\n );\n assert.strictEqual(result.limitParamName, limitKey);\n assert.strictEqual(\n result.limitKeyword,\n getExpectedKeyword(limitKey, CURSOR_LIMIT_REGEXES),\n );\n });\n }\n }\n test('should not detect cursor if one param is not in query', () => {\n const op = createOperation([hParam('cursor'), qParam('first')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should not detect with two cursor-like params and no limit', () => {\n const op = createOperation([qParam('cursor'), qParam('after')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n });\n\n describe('Pagination Type Precedence', () => {\n test('Offset should take precedence over Page (e.g., \"skip\", \"limit\", \"page\")', () => {\n // This test relies on the actual implementation's precedence logic.\n // The simple mock might not reflect this correctly.\n const op = createOperation([\n qParam('skip'),\n qParam('limit'),\n qParam('page'),\n ]);\n const result = guessPagination(op); // Assuming 'skip'/'limit' makes it 'offset'\n assert.strictEqual(result.type, 'offset');\n if (result.type === 'offset') {\n // Type guard for TS\n assert.strictEqual(result.offsetParamName, 'skip');\n assert.strictEqual(result.limitParamName, 'limit');\n }\n });\n\n test('Offset should take precedence over Cursor (e.g., \"offset\", \"count\", \"after_token\")', () => {\n const op = createOperation([\n qParam('offset'),\n qParam('count'),\n qParam('after_token'),\n ]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'offset');\n if (result.type === 'offset') {\n assert.strictEqual(result.offsetParamName, 'offset');\n assert.strictEqual(result.limitParamName, 'count');\n }\n });\n\n test('Page should take precedence over Cursor (e.g., \"page\", \"size\", \"next_cursor\")', () => {\n const op = createOperation([\n qParam('page'),\n qParam('size'),\n qParam('next_cursor'),\n ]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'page');\n if (result.type === 'page') {\n assert.strictEqual(result.pageNumberParamName, 'page');\n assert.strictEqual(result.pageSizeParamName, 'size');\n }\n });\n\n test('Params like \"page\" and \"limit\" should resolve to Page pagination', () => {\n const op = createOperation([qParam('page'), qParam('limit')]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'page');\n if (result.type === 'page') {\n assert.strictEqual(result.pageNumberParamName, 'page');\n assert.strictEqual(result.pageSizeParamName, 'limit');\n }\n });\n });\n\n describe('Regex Specificity and Word Boundaries', () => {\n // These tests are highly dependent on the actual regexes and findParamAndKeyword logic.\n // The simple mock won't pass these accurately.\n test('should not match \"custom_offset\" as \"offset\" due to word boundary (with real implementation)', () => {\n const op = createOperation([\n qParam('custom_offset_param'),\n qParam('limit'),\n ]);\n // Expectation with real implementation:\n // assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n // With current simple mock, this might pass if 'limit' alone is not enough.\n assert.ok(\n true,\n 'Test needs real implementation for accurate regex boundary check',\n );\n });\n\n test('should match \"offset_custom\" for \"offset\" keyword (with real implementation)', () => {\n const op = createOperation([qParam('offset_custom'), qParam('limit')]);\n // Expectation with real implementation:\n // const result = guessPagination(op);\n // assert.strictEqual(result.type, 'offset');\n // assert.strictEqual(result.offsetParamName, 'offset_custom');\n // assert.strictEqual(result.offsetKeyword, 'offset');\n assert.ok(\n true,\n 'Test needs real implementation for accurate keyword extraction',\n );\n });\n\n test('should match \"page\" exactly for page number, not \"my_page_details\" (with real implementation)', () => {\n const op = createOperation([qParam('my_page_details'), qParam('size')]);\n // assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n assert.ok(\n true,\n 'Test needs real implementation for exact regex matching',\n );\n });\n\n test('should match \"p\" exactly for page number (with real implementation)', () => {\n const op = createOperation([qParam('p'), qParam('size')]);\n // const result = guessPagination(op);\n // assert.strictEqual(result.type, 'page');\n // assert.strictEqual(result.pageNumberParamName, 'p');\n // assert.strictEqual(result.pageNumberKeyword, 'p');\n assert.ok(\n true,\n 'Test needs real implementation for exact regex matching',\n );\n });\n });\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import assert from 'node:assert/strict';\nimport { describe, test } from 'node:test';\nimport type { ParameterObject } from 'openapi3-ts/oas31';\n\nimport type { TunedOperationObject } from '../types.ts';\nimport {\n CURSOR_LIMIT_REGEXES,\n CURSOR_REGEXES,\n GENERIC_LIMIT_PARAM_REGEXES,\n OFFSET_PARAM_REGEXES,\n PAGE_NUMBER_REGEXES,\n PAGE_SIZE_REGEXES,\n guessPagination,\n} from './guess-pagination.ts';\n\nfunction createOperation(params: ParameterObject[]): TunedOperationObject {\n return {\n 'x-fn-name': 'testFunction',\n tags: ['test'],\n operationId: 'testOperation',\n parameters: params,\n requestBody: { content: {} },\n responses: {},\n };\n}\n\nfunction qParam(name: string): ParameterObject {\n return {\n name,\n in: 'query',\n required: false,\n schema: {\n type: 'string',\n },\n };\n}\n\nfunction hParam(name: string): ParameterObject {\n return {\n name,\n in: 'header',\n required: false,\n schema: {\n type: 'string',\n },\n };\n}\nfunction pParam(name: string): ParameterObject {\n return {\n name,\n in: 'path',\n required: false,\n schema: {\n type: 'string',\n },\n };\n}\nfunction getExpectedKeyword(paramName: string, regexArray: RegExp[]): string {\n for (const regex of regexArray) {\n const match = paramName.match(regex);\n if (match) {\n return match[0];\n }\n }\n // This might return undefined if the paramName is not expected to match any regex in the array,\n // which is fine for negative test cases or if the mock doesn't perfectly align.\n // For positive cases, ensure your actual implementation and regexes would provide a match.\n return paramName; // Fallback for mock simplicity, real tests need accurate keyword\n}\n\ndescribe('guessPagination()', () => {\n describe('No Pagination Detected', () => {\n test('should return \"none\" for an operation with an empty parameters array', () => {\n const op = createOperation([]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should return \"none\" for an operation with undefined parameters', () => {\n const op = createOperation(undefined as never);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should return \"none\" for non-pagination query parameters', () => {\n const op = createOperation([qParam('search'), qParam('filterBy')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should return \"none\" if relevant parameters are not in \"query\"', () => {\n const op = createOperation([hParam('offset'), hParam('limit')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should return \"none\" if only one part of a pair is present (e.g., only offset)', () => {\n assert.deepStrictEqual(\n guessPagination(createOperation([qParam('offset')])),\n { type: 'none' },\n 'Only offset',\n );\n assert.deepStrictEqual(\n guessPagination(createOperation([qParam('page')])),\n { type: 'none' },\n 'Only page',\n );\n assert.deepStrictEqual(\n guessPagination(createOperation([qParam('cursor')])),\n { type: 'none' },\n 'Only cursor',\n );\n assert.deepStrictEqual(\n guessPagination(createOperation([qParam('limit')])),\n { type: 'none' },\n 'Only limit',\n );\n });\n\n test('should return \"none\" for mixed non-query and insufficient query params', () => {\n const op = createOperation([\n pParam('userId'),\n qParam('offset'),\n hParam('X-Request-ID'),\n ]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n });\n\n describe('Offset Pagination Detection', () => {\n const testOffsetKeywords = [\n 'offset',\n 'skip',\n 'start',\n 'start_index',\n 'starting_at',\n 'from',\n 'Offset',\n 'SKIP',\n ];\n const testLimitKeywords = [\n 'limit',\n 'count',\n 'size',\n 'page_size',\n 'pageSize',\n 'max_results',\n 'take',\n 'Limit',\n 'COUNT',\n ];\n\n for (const offsetKey of testOffsetKeywords) {\n for (const limitKey of testLimitKeywords) {\n if (offsetKey.toLowerCase() === limitKey.toLowerCase()) continue;\n\n test(`should detect offset with \"${offsetKey}\" and \"${limitKey}\"`, () => {\n const op = createOperation([qParam(offsetKey), qParam(limitKey)]);\n const result = guessPagination(op);\n // Note: With a simple mock, these detailed assertions might fail.\n // They are designed for the actual implementation.\n assert.strictEqual(\n result.type,\n 'offset',\n `Failed for ${offsetKey}, ${limitKey}`,\n );\n assert.strictEqual(result.offsetParamName, offsetKey);\n assert.strictEqual(\n result.offsetKeyword,\n getExpectedKeyword(offsetKey, OFFSET_PARAM_REGEXES),\n );\n assert.strictEqual(result.limitParamName, limitKey);\n assert.strictEqual(\n result.limitKeyword,\n getExpectedKeyword(limitKey, GENERIC_LIMIT_PARAM_REGEXES),\n );\n });\n }\n }\n\n test('should not detect offset if one param is not in query', () => {\n const op = createOperation([hParam('offset'), qParam('limit')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should not detect with two offset-like params and no limit', () => {\n const op = createOperation([qParam('offset'), qParam('skip')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should correctly handle params in different order', () => {\n const op = createOperation([qParam('limit'), qParam('offset')]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'offset');\n assert.strictEqual(result.offsetParamName, 'offset');\n assert.strictEqual(result.limitParamName, 'limit');\n });\n\n test('should handle extra non-pagination params', () => {\n const op = createOperation([\n qParam('filter'),\n qParam('offset'),\n qParam('sort'),\n qParam('limit'),\n ]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'offset');\n assert.strictEqual(result.offsetParamName, 'offset');\n assert.strictEqual(result.limitParamName, 'limit');\n });\n });\n\n describe('Page Pagination Detection', () => {\n const testPageNumKeywords = [\n 'page',\n 'p',\n 'page_number',\n 'pageNum',\n 'page_idx',\n 'Page',\n 'P',\n ];\n const testPageSizeKeywords = [\n 'page_size',\n 'pageSize',\n 'size',\n 'limit',\n 'count',\n 'per_page',\n 'per-page',\n 'num_items',\n 'Size',\n 'LIMIT',\n ];\n\n for (const pageKey of testPageNumKeywords) {\n for (const sizeKey of testPageSizeKeywords) {\n if (pageKey.toLowerCase() === sizeKey.toLowerCase()) continue;\n\n test(`should detect page with \"${pageKey}\" and \"${sizeKey}\"`, () => {\n const op = createOperation([qParam(pageKey), qParam(sizeKey)]);\n const result = guessPagination(op);\n assert.strictEqual(\n result.type,\n 'page',\n `Failed for ${pageKey}, ${sizeKey}`,\n );\n assert.strictEqual(result.pageNumberParamName, pageKey);\n assert.strictEqual(\n result.pageNumberKeyword,\n getExpectedKeyword(pageKey, PAGE_NUMBER_REGEXES),\n );\n assert.strictEqual(result.pageSizeParamName, sizeKey);\n assert.strictEqual(\n result.pageSizeKeyword,\n getExpectedKeyword(sizeKey, PAGE_SIZE_REGEXES),\n );\n });\n }\n }\n test('should not detect page if one param is not in query', () => {\n const op = createOperation([hParam('page'), qParam('size')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should not detect with two page-number-like params and no size', () => {\n const op = createOperation([qParam('page'), qParam('page_number')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n });\n\n describe('Cursor Pagination Detection', () => {\n const testCursorKeywords = [\n 'cursor',\n 'after',\n 'before_cursor',\n 'next_page_token',\n 'pageToken',\n 'continuation_token',\n 'Cursor',\n 'AFTER',\n ];\n const testCursorLimitKeywords = [\n 'limit',\n 'count',\n 'size',\n 'first',\n 'last',\n 'page_size',\n 'num_items',\n 'take',\n 'First',\n 'LAST',\n ];\n\n for (const cursorKey of testCursorKeywords) {\n for (const limitKey of testCursorLimitKeywords) {\n if (cursorKey.toLowerCase() === limitKey.toLowerCase()) continue;\n\n test(`should detect cursor with \"${cursorKey}\" and \"${limitKey}\"`, () => {\n const op = createOperation([qParam(cursorKey), qParam(limitKey)]);\n const result = guessPagination(op);\n assert.strictEqual(\n result.type,\n 'cursor',\n `Failed for ${cursorKey}, ${limitKey}`,\n );\n assert.strictEqual(result.cursorParamName, cursorKey);\n assert.strictEqual(\n result.cursorKeyword,\n getExpectedKeyword(cursorKey, CURSOR_REGEXES),\n );\n assert.strictEqual(result.limitParamName, limitKey);\n assert.strictEqual(\n result.limitKeyword,\n getExpectedKeyword(limitKey, CURSOR_LIMIT_REGEXES),\n );\n });\n }\n }\n test('should not detect cursor if one param is not in query', () => {\n const op = createOperation([hParam('cursor'), qParam('first')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n\n test('should not detect with two cursor-like params and no limit', () => {\n const op = createOperation([qParam('cursor'), qParam('after')]);\n assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n });\n });\n\n describe('Pagination Type Precedence', () => {\n test('Offset should take precedence over Page (e.g., \"skip\", \"limit\", \"page\")', () => {\n // This test relies on the actual implementation's precedence logic.\n // The simple mock might not reflect this correctly.\n const op = createOperation([\n qParam('skip'),\n qParam('limit'),\n qParam('page'),\n ]);\n const result = guessPagination(op); // Assuming 'skip'/'limit' makes it 'offset'\n assert.strictEqual(result.type, 'offset');\n if (result.type === 'offset') {\n // Type guard for TS\n assert.strictEqual(result.offsetParamName, 'skip');\n assert.strictEqual(result.limitParamName, 'limit');\n }\n });\n\n test('Offset should take precedence over Cursor (e.g., \"offset\", \"count\", \"after_token\")', () => {\n const op = createOperation([\n qParam('offset'),\n qParam('count'),\n qParam('after_token'),\n ]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'offset');\n if (result.type === 'offset') {\n assert.strictEqual(result.offsetParamName, 'offset');\n assert.strictEqual(result.limitParamName, 'count');\n }\n });\n\n test('Page should take precedence over Cursor (e.g., \"page\", \"size\", \"next_cursor\")', () => {\n const op = createOperation([\n qParam('page'),\n qParam('size'),\n qParam('next_cursor'),\n ]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'page');\n if (result.type === 'page') {\n assert.strictEqual(result.pageNumberParamName, 'page');\n assert.strictEqual(result.pageSizeParamName, 'size');\n }\n });\n\n test('Params like \"page\" and \"limit\" should resolve to Page pagination', () => {\n const op = createOperation([qParam('page'), qParam('limit')]);\n const result = guessPagination(op);\n assert.strictEqual(result.type, 'page');\n if (result.type === 'page') {\n assert.strictEqual(result.pageNumberParamName, 'page');\n assert.strictEqual(result.pageSizeParamName, 'limit');\n }\n });\n });\n\n describe('Regex Specificity and Word Boundaries', () => {\n // These tests are highly dependent on the actual regexes and findParamAndKeyword logic.\n // The simple mock won't pass these accurately.\n test('should not match \"custom_offset\" as \"offset\" due to word boundary (with real implementation)', () => {\n const op = createOperation([\n qParam('custom_offset_param'),\n qParam('limit'),\n ]);\n // Expectation with real implementation:\n // assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n // With current simple mock, this might pass if 'limit' alone is not enough.\n assert.ok(\n true,\n 'Test needs real implementation for accurate regex boundary check',\n );\n });\n\n test('should match \"offset_custom\" for \"offset\" keyword (with real implementation)', () => {\n const op = createOperation([qParam('offset_custom'), qParam('limit')]);\n // Expectation with real implementation:\n // const result = guessPagination(op);\n // assert.strictEqual(result.type, 'offset');\n // assert.strictEqual(result.offsetParamName, 'offset_custom');\n // assert.strictEqual(result.offsetKeyword, 'offset');\n assert.ok(\n true,\n 'Test needs real implementation for accurate keyword extraction',\n );\n });\n\n test('should match \"page\" exactly for page number, not \"my_page_details\" (with real implementation)', () => {\n const op = createOperation([qParam('my_page_details'), qParam('size')]);\n // assert.deepStrictEqual(guessPagination(op), { type: 'none' });\n assert.ok(\n true,\n 'Test needs real implementation for exact regex matching',\n );\n });\n\n test('should match \"p\" exactly for page number (with real implementation)', () => {\n const op = createOperation([qParam('p'), qParam('size')]);\n // const result = guessPagination(op);\n // assert.strictEqual(result.type, 'page');\n // assert.strictEqual(result.pageNumberParamName, 'p');\n // assert.strictEqual(result.pageNumberKeyword, 'p');\n assert.ok(\n true,\n 'Test needs real implementation for exact regex matching',\n );\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/lib/sidebar.d.ts
CHANGED
|
@@ -19,28 +19,9 @@ export type CategoryItem = {
|
|
|
19
19
|
items: NavItem[];
|
|
20
20
|
};
|
|
21
21
|
export type SidebarData = CategoryItem[];
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
groups: Group[];
|
|
26
|
-
}
|
|
27
|
-
export interface Group {
|
|
28
|
-
id: string;
|
|
29
|
-
title: string;
|
|
30
|
-
description?: string;
|
|
31
|
-
navigationGroup: string;
|
|
32
|
-
sections: Section[];
|
|
33
|
-
beta?: boolean;
|
|
34
|
-
legacy?: boolean;
|
|
35
|
-
}
|
|
36
|
-
export interface Section {
|
|
37
|
-
type: 'endpoint' | 'object' | 'overview';
|
|
38
|
-
key: string;
|
|
39
|
-
path: string;
|
|
40
|
-
}
|
|
41
|
-
export interface NavigationGroup {
|
|
42
|
-
id: string;
|
|
43
|
-
title: string;
|
|
44
|
-
beta?: boolean;
|
|
22
|
+
export interface TagGroups {
|
|
23
|
+
name: string;
|
|
24
|
+
tags: string[];
|
|
45
25
|
}
|
|
26
|
+
export declare function toSidebar(spec: OurOpenAPIObject): SidebarData;
|
|
46
27
|
//# sourceMappingURL=sidebar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/lib/sidebar.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/lib/sidebar.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,YAAY,EAAE,CAAC;AAEzC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,eA8B/C"}
|
package/dist/lib/sidebar.js
CHANGED
|
@@ -1,74 +1,31 @@
|
|
|
1
1
|
import { camelcase } from "stringcase";
|
|
2
|
+
import { notNullOrUndefined } from "@sdk-it/core/file-system.js";
|
|
2
3
|
import { forEachOperation } from "./for-each-operation.js";
|
|
3
|
-
function createOAIMeta(spec) {
|
|
4
|
-
spec.paths ??= {};
|
|
5
|
-
const navigationGroups = {
|
|
6
|
-
api: { id: "api", title: "API" }
|
|
7
|
-
};
|
|
8
|
-
const groups = {};
|
|
9
|
-
forEachOperation(spec, (entry, operation) => {
|
|
10
|
-
const tag = entry.tag;
|
|
11
|
-
groups[tag] ??= {
|
|
12
|
-
id: tag,
|
|
13
|
-
title: tag,
|
|
14
|
-
description: spec.tags?.find((t) => t.name === tag)?.description,
|
|
15
|
-
navigationGroup: "api",
|
|
16
|
-
sections: []
|
|
17
|
-
};
|
|
18
|
-
groups[tag].sections.push({
|
|
19
|
-
type: "endpoint",
|
|
20
|
-
key: operation.operationId,
|
|
21
|
-
path: entry.path
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
return {
|
|
25
|
-
groups: Object.values(groups),
|
|
26
|
-
navigationGroups: Object.values(navigationGroups)
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function getOperationById(spec, operationId) {
|
|
30
|
-
let operation;
|
|
31
|
-
forEachOperation(spec, (entry, op) => {
|
|
32
|
-
if (op.operationId === operationId) {
|
|
33
|
-
operation = op;
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
return operation;
|
|
37
|
-
}
|
|
38
4
|
function toSidebar(spec) {
|
|
39
|
-
const openapi = spec;
|
|
40
5
|
const sidebar = spec["x-docs"];
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const groupItems = [];
|
|
48
|
-
for (const item of group) {
|
|
49
|
-
const subitems = (item.sections ?? []).filter((it) => it.type === "endpoint").map((section) => {
|
|
50
|
-
const operation = getOperationById(spec, section.key);
|
|
51
|
-
const title = operation?.["x-oaiMeta"]?.name || operation?.summary || section.key;
|
|
6
|
+
for (const tagGroup of spec["x-tagGroups"]) {
|
|
7
|
+
sidebar.push({
|
|
8
|
+
id: camelcase(tagGroup.name),
|
|
9
|
+
category: tagGroup.name,
|
|
10
|
+
items: tagGroup.tags.map((tag) => {
|
|
11
|
+
const tagSpec = spec.tags?.find((t) => t.name === tag);
|
|
52
12
|
return {
|
|
53
|
-
id:
|
|
54
|
-
|
|
55
|
-
|
|
13
|
+
id: crypto.randomUUID(),
|
|
14
|
+
description: tagSpec?.description,
|
|
15
|
+
title: tagSpec ? tagSpec["x-displayName"] || tagSpec.name || tag : tag,
|
|
16
|
+
items: forEachOperation(spec, (entry, operation) => {
|
|
17
|
+
if (operation.tags.includes(tag)) {
|
|
18
|
+
const title = operation.summary || operation.operationId;
|
|
19
|
+
return {
|
|
20
|
+
id: operation.operationId,
|
|
21
|
+
title,
|
|
22
|
+
url: `${camelcase(tag)}/${camelcase(operation.operationId)}`
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}).filter(notNullOrUndefined)
|
|
56
27
|
};
|
|
57
|
-
})
|
|
58
|
-
if (subitems.length === 0) continue;
|
|
59
|
-
groupItems.push({
|
|
60
|
-
id: item.id,
|
|
61
|
-
title: item.title,
|
|
62
|
-
// url: `/${item.id}`,
|
|
63
|
-
description: item.description,
|
|
64
|
-
items: subitems
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
if (groupItems.length === 0) continue;
|
|
68
|
-
sidebar.push({
|
|
69
|
-
id: navGroup.id,
|
|
70
|
-
category: navGroup.title,
|
|
71
|
-
items: groupItems
|
|
28
|
+
})
|
|
72
29
|
});
|
|
73
30
|
}
|
|
74
31
|
return sidebar;
|
package/dist/lib/sidebar.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/sidebar.ts"],
|
|
4
|
-
"sourcesContent": ["import
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": [
|
|
4
|
+
"sourcesContent": ["import { camelcase } from 'stringcase';\n\nimport { notNullOrUndefined } from '@sdk-it/core/file-system.js';\n\nimport { forEachOperation } from './for-each-operation.js';\nimport type { OurOpenAPIObject } from './types.js';\n\nexport type ChildNavItem = {\n id: string;\n title: string;\n url: string;\n};\n\nexport type NavItem = {\n id: string;\n title: string;\n description?: string;\n url?: string;\n items?: ChildNavItem[];\n content?: string; // Markdown content\n};\n\nexport type CategoryItem = {\n id: string;\n category: string;\n description?: string;\n items: NavItem[];\n};\n\nexport type SidebarData = CategoryItem[];\n\nexport interface TagGroups {\n name: string;\n tags: string[];\n}\n\nexport function toSidebar(spec: OurOpenAPIObject) {\n const sidebar: SidebarData = spec['x-docs'];\n for (const tagGroup of spec['x-tagGroups']) {\n sidebar.push({\n id: camelcase(tagGroup.name),\n category: tagGroup.name,\n items: tagGroup.tags.map((tag) => {\n const tagSpec = spec.tags?.find((t) => t.name === tag);\n return {\n id: crypto.randomUUID(),\n description: tagSpec?.description,\n title: tagSpec\n ? tagSpec['x-displayName'] || tagSpec.name || tag\n : tag,\n items: forEachOperation(spec, (entry, operation) => {\n if (operation.tags.includes(tag)) {\n const title = operation.summary || operation.operationId;\n return {\n id: operation.operationId,\n title,\n url: `${camelcase(tag)}/${camelcase(operation.operationId)}`,\n };\n }\n return null;\n }).filter(notNullOrUndefined),\n };\n }),\n });\n }\n return sidebar;\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAE1B,SAAS,0BAA0B;AAEnC,SAAS,wBAAwB;AAgC1B,SAAS,UAAU,MAAwB;AAChD,QAAM,UAAuB,KAAK,QAAQ;AAC1C,aAAW,YAAY,KAAK,aAAa,GAAG;AAC1C,YAAQ,KAAK;AAAA,MACX,IAAI,UAAU,SAAS,IAAI;AAAA,MAC3B,UAAU,SAAS;AAAA,MACnB,OAAO,SAAS,KAAK,IAAI,CAAC,QAAQ;AAChC,cAAM,UAAU,KAAK,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,GAAG;AACrD,eAAO;AAAA,UACL,IAAI,OAAO,WAAW;AAAA,UACtB,aAAa,SAAS;AAAA,UACtB,OAAO,UACH,QAAQ,eAAe,KAAK,QAAQ,QAAQ,MAC5C;AAAA,UACJ,OAAO,iBAAiB,MAAM,CAAC,OAAO,cAAc;AAClD,gBAAI,UAAU,KAAK,SAAS,GAAG,GAAG;AAChC,oBAAM,QAAQ,UAAU,WAAW,UAAU;AAC7C,qBAAO;AAAA,gBACL,IAAI,UAAU;AAAA,gBACd;AAAA,gBACA,KAAK,GAAG,UAAU,GAAG,CAAC,IAAI,UAAU,UAAU,WAAW,CAAC;AAAA,cAC5D;AAAA,YACF;AACA,mBAAO;AAAA,UACT,CAAC,EAAE,OAAO,kBAAkB;AAAA,QAC9B;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { OperationObject, ParameterObject, SchemaObject, SecurityRequirementObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import type { OurOpenAPIObject, OurRequestBodyObject } from './types.js';
|
|
3
|
+
export declare function patchParameters(spec: OurOpenAPIObject, schema: SchemaObject, parameters: ParameterObject[], security: SecurityRequirementObject[]): void;
|
|
4
|
+
export declare function tuneRequestBody(spec: OurOpenAPIObject, operationId: string, operation: OperationObject, parameters: ParameterObject[], security: SecurityRequirementObject[]): OurRequestBodyObject;
|
|
5
|
+
//# sourceMappingURL=tune-request-body.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tune-request-body.d.ts","sourceRoot":"","sources":["../../src/lib/tune-request-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EAEf,YAAY,EACZ,yBAAyB,EAC1B,MAAM,mBAAmB,CAAC;AAO3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEzE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,eAAe,EAAE,EAC7B,QAAQ,EAAE,yBAAyB,EAAE,QA4BtC;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,gBAAgB,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,eAAe,EAC1B,UAAU,EAAE,eAAe,EAAE,EAC7B,QAAQ,EAAE,yBAAyB,EAAE,GACpC,oBAAoB,CA+DtB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { followRef, isRef } from "@sdk-it/core/ref.js";
|
|
2
|
+
import { isEmpty } from "@sdk-it/core/utils.js";
|
|
3
|
+
import { findUniqueSchemaName } from "./find-unique-schema-name.js";
|
|
4
|
+
import { securityToOptions } from "./security.js";
|
|
5
|
+
function patchParameters(spec, schema, parameters, security) {
|
|
6
|
+
const securitySchemes = spec.components?.securitySchemes ?? {};
|
|
7
|
+
const securityOptions = securityToOptions(spec, security, securitySchemes);
|
|
8
|
+
let required = Array.isArray(schema.required) ? schema.required : [];
|
|
9
|
+
schema["x-properties"] ??= {};
|
|
10
|
+
for (const param of parameters) {
|
|
11
|
+
if (param.required) {
|
|
12
|
+
required.push(param.name);
|
|
13
|
+
}
|
|
14
|
+
schema["x-properties"][param.name] = {
|
|
15
|
+
"x-in": param.in,
|
|
16
|
+
...isRef(param.schema) ? followRef(spec, param.schema.$ref) : param.schema ?? { type: "string" }
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
for (const param of securityOptions) {
|
|
20
|
+
required = required.filter((name) => name !== param.name);
|
|
21
|
+
schema["x-properties"][param.name] = {
|
|
22
|
+
"x-in": "header",
|
|
23
|
+
...isRef(param.schema) ? followRef(spec, param.schema.$ref) : param.schema ?? { type: "string" }
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
schema["x-required"] = required;
|
|
27
|
+
}
|
|
28
|
+
function tuneRequestBody(spec, operationId, operation, parameters, security) {
|
|
29
|
+
const inputName = findUniqueSchemaName(spec, operationId, [
|
|
30
|
+
"input",
|
|
31
|
+
"payload",
|
|
32
|
+
"request"
|
|
33
|
+
]);
|
|
34
|
+
const requestBody = isRef(operation.requestBody) ? followRef(spec, operation.requestBody.$ref) : operation.requestBody ?? {
|
|
35
|
+
content: {},
|
|
36
|
+
required: false
|
|
37
|
+
};
|
|
38
|
+
if (isEmpty(requestBody.content)) {
|
|
39
|
+
const schema = {
|
|
40
|
+
"x-inputname": inputName,
|
|
41
|
+
"x-requestbody": true
|
|
42
|
+
};
|
|
43
|
+
patchParameters(spec, schema, parameters, security);
|
|
44
|
+
const tuned = {
|
|
45
|
+
...requestBody,
|
|
46
|
+
content: {
|
|
47
|
+
"application/empty": {
|
|
48
|
+
schema: { $ref: `#/components/schemas/${inputName}` }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
spec.components.schemas[inputName] = schema;
|
|
53
|
+
return tuned;
|
|
54
|
+
}
|
|
55
|
+
for (const contentType in requestBody.content) {
|
|
56
|
+
const mediaType = requestBody.content[contentType];
|
|
57
|
+
let schema;
|
|
58
|
+
switch (true) {
|
|
59
|
+
case isRef(mediaType.schema):
|
|
60
|
+
schema = followRef(spec, mediaType.schema.$ref);
|
|
61
|
+
break;
|
|
62
|
+
case isEmpty(mediaType.schema):
|
|
63
|
+
schema ??= {};
|
|
64
|
+
console.warn(
|
|
65
|
+
`Request body schema for content type "${contentType}" is empty.`
|
|
66
|
+
);
|
|
67
|
+
break;
|
|
68
|
+
default:
|
|
69
|
+
schema = mediaType.schema;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
patchParameters(spec, schema, parameters, security);
|
|
73
|
+
spec.components.schemas[inputName] = {
|
|
74
|
+
...schema,
|
|
75
|
+
"x-requestbody": true,
|
|
76
|
+
"x-inputname": inputName
|
|
77
|
+
};
|
|
78
|
+
requestBody.content[contentType].schema = {
|
|
79
|
+
$ref: `#/components/schemas/${inputName}`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return requestBody;
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
patchParameters,
|
|
86
|
+
tuneRequestBody
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=tune-request-body.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/tune-request-body.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n OperationObject,\n ParameterObject,\n RequestBodyObject,\n SchemaObject,\n SecurityRequirementObject,\n} from 'openapi3-ts/oas31';\n\nimport { followRef, isRef } from '@sdk-it/core/ref.js';\nimport { isEmpty } from '@sdk-it/core/utils.js';\n\nimport { findUniqueSchemaName } from './find-unique-schema-name.js';\nimport { securityToOptions } from './security.js';\nimport type { OurOpenAPIObject, OurRequestBodyObject } from './types.js';\n\nexport function patchParameters(\n spec: OurOpenAPIObject,\n schema: SchemaObject,\n parameters: ParameterObject[],\n security: SecurityRequirementObject[],\n) {\n const securitySchemes = spec.components?.securitySchemes ?? {};\n const securityOptions = securityToOptions(spec, security, securitySchemes);\n\n let required = Array.isArray(schema.required) ? schema.required : [];\n schema['x-properties'] ??= {};\n for (const param of parameters) {\n if (param.required) {\n required.push(param.name);\n }\n schema['x-properties'][param.name] = {\n 'x-in': param.in,\n ...(isRef(param.schema)\n ? followRef<SchemaObject>(spec, param.schema.$ref)\n : (param.schema ?? { type: 'string' })),\n };\n }\n for (const param of securityOptions) {\n required = required.filter((name) => name !== param.name);\n schema['x-properties'][param.name] = {\n 'x-in': 'header',\n ...(isRef(param.schema)\n ? followRef<SchemaObject>(spec, param.schema.$ref)\n : (param.schema ?? { type: 'string' })),\n };\n }\n schema['x-required'] = required;\n}\n\nexport function tuneRequestBody(\n spec: OurOpenAPIObject,\n operationId: string,\n operation: OperationObject,\n parameters: ParameterObject[],\n security: SecurityRequirementObject[],\n): OurRequestBodyObject {\n const inputName = findUniqueSchemaName(spec, operationId, [\n 'input',\n 'payload',\n 'request',\n ]);\n const requestBody = isRef(operation.requestBody)\n ? followRef<RequestBodyObject>(spec, operation.requestBody.$ref)\n : (operation.requestBody ?? {\n content: {},\n required: false,\n });\n if (isEmpty(requestBody.content)) {\n const schema: SchemaObject = {\n 'x-inputname': inputName,\n 'x-requestbody': true,\n };\n patchParameters(spec, schema, parameters, security);\n const tuned: OurRequestBodyObject = {\n ...requestBody,\n content: {\n 'application/empty': {\n schema: { $ref: `#/components/schemas/${inputName}` },\n },\n },\n };\n\n spec.components.schemas[inputName] = schema;\n return tuned;\n }\n for (const contentType in requestBody.content) {\n const mediaType = requestBody.content[contentType];\n let schema: SchemaObject | undefined;\n\n switch (true) {\n case isRef(mediaType.schema):\n schema = followRef<SchemaObject>(spec, mediaType.schema.$ref);\n // we cannot use the model name as inputName as it might be used in other places that are not request bodies\n // inputName = parseRef(mediaType.schema.$ref).model;\n break;\n case isEmpty(mediaType.schema):\n schema ??= {}; // default to empty schema if not defined\n console.warn(\n `Request body schema for content type \"${contentType}\" is empty.`,\n );\n break;\n default:\n schema = mediaType.schema;\n break;\n }\n\n patchParameters(spec, schema, parameters, security);\n spec.components.schemas[inputName] = {\n ...schema,\n 'x-requestbody': true,\n 'x-inputname': inputName,\n };\n\n requestBody.content[contentType].schema = {\n $ref: `#/components/schemas/${inputName}`,\n };\n }\n return requestBody as OurRequestBodyObject;\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAS,WAAW,aAAa;AACjC,SAAS,eAAe;AAExB,SAAS,4BAA4B;AACrC,SAAS,yBAAyB;AAG3B,SAAS,gBACd,MACA,QACA,YACA,UACA;AACA,QAAM,kBAAkB,KAAK,YAAY,mBAAmB,CAAC;AAC7D,QAAM,kBAAkB,kBAAkB,MAAM,UAAU,eAAe;AAEzE,MAAI,WAAW,MAAM,QAAQ,OAAO,QAAQ,IAAI,OAAO,WAAW,CAAC;AACnE,SAAO,cAAc,MAAM,CAAC;AAC5B,aAAW,SAAS,YAAY;AAC9B,QAAI,MAAM,UAAU;AAClB,eAAS,KAAK,MAAM,IAAI;AAAA,IAC1B;AACA,WAAO,cAAc,EAAE,MAAM,IAAI,IAAI;AAAA,MACnC,QAAQ,MAAM;AAAA,MACd,GAAI,MAAM,MAAM,MAAM,IAClB,UAAwB,MAAM,MAAM,OAAO,IAAI,IAC9C,MAAM,UAAU,EAAE,MAAM,SAAS;AAAA,IACxC;AAAA,EACF;AACA,aAAW,SAAS,iBAAiB;AACnC,eAAW,SAAS,OAAO,CAAC,SAAS,SAAS,MAAM,IAAI;AACxD,WAAO,cAAc,EAAE,MAAM,IAAI,IAAI;AAAA,MACnC,QAAQ;AAAA,MACR,GAAI,MAAM,MAAM,MAAM,IAClB,UAAwB,MAAM,MAAM,OAAO,IAAI,IAC9C,MAAM,UAAU,EAAE,MAAM,SAAS;AAAA,IACxC;AAAA,EACF;AACA,SAAO,YAAY,IAAI;AACzB;AAEO,SAAS,gBACd,MACA,aACA,WACA,YACA,UACsB;AACtB,QAAM,YAAY,qBAAqB,MAAM,aAAa;AAAA,IACxD;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,cAAc,MAAM,UAAU,WAAW,IAC3C,UAA6B,MAAM,UAAU,YAAY,IAAI,IAC5D,UAAU,eAAe;AAAA,IACxB,SAAS,CAAC;AAAA,IACV,UAAU;AAAA,EACZ;AACJ,MAAI,QAAQ,YAAY,OAAO,GAAG;AAChC,UAAM,SAAuB;AAAA,MAC3B,eAAe;AAAA,MACf,iBAAiB;AAAA,IACnB;AACA,oBAAgB,MAAM,QAAQ,YAAY,QAAQ;AAClD,UAAM,QAA8B;AAAA,MAClC,GAAG;AAAA,MACH,SAAS;AAAA,QACP,qBAAqB;AAAA,UACnB,QAAQ,EAAE,MAAM,wBAAwB,SAAS,GAAG;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAEA,SAAK,WAAW,QAAQ,SAAS,IAAI;AACrC,WAAO;AAAA,EACT;AACA,aAAW,eAAe,YAAY,SAAS;AAC7C,UAAM,YAAY,YAAY,QAAQ,WAAW;AACjD,QAAI;AAEJ,YAAQ,MAAM;AAAA,MACZ,KAAK,MAAM,UAAU,MAAM;AACzB,iBAAS,UAAwB,MAAM,UAAU,OAAO,IAAI;AAG5D;AAAA,MACF,KAAK,QAAQ,UAAU,MAAM;AAC3B,mBAAW,CAAC;AACZ,gBAAQ;AAAA,UACN,yCAAyC,WAAW;AAAA,QACtD;AACA;AAAA,MACF;AACE,iBAAS,UAAU;AACnB;AAAA,IACJ;AAEA,oBAAgB,MAAM,QAAQ,YAAY,QAAQ;AAClD,SAAK,WAAW,QAAQ,SAAS,IAAI;AAAA,MACnC,GAAG;AAAA,MACH,iBAAiB;AAAA,MACjB,eAAe;AAAA,IACjB;AAEA,gBAAY,QAAQ,WAAW,EAAE,SAAS;AAAA,MACxC,MAAM,wBAAwB,SAAS;AAAA,IACzC;AAAA,EACF;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { OperationObject } from 'openapi3-ts/oas31';
|
|
2
|
+
import { type ResponsesConfig } from './options.js';
|
|
3
|
+
import type { OurOpenAPIObject } from './types.js';
|
|
4
|
+
export declare function resolveResponses(spec: OurOpenAPIObject, operationId: string, operation: OperationObject, responsesConfig?: ResponsesConfig): import("openapi3-ts/oas31").ResponsesObject;
|
|
5
|
+
//# sourceMappingURL=tune-response.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tune-response.d.ts","sourceRoot":"","sources":["../../src/lib/tune-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,mBAAmB,CAAC;AAY3B,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,gBAAgB,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,eAAe,EAC1B,eAAe,CAAC,EAAE,eAAe,+CAuHlC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { isRef, parseRef, resolveRef } from "@sdk-it/core/ref.js";
|
|
2
|
+
import { isEmpty, pascalcase } from "@sdk-it/core/utils.js";
|
|
3
|
+
import { findUniqueSchemaName } from "./find-unique-schema-name.js";
|
|
4
|
+
import {
|
|
5
|
+
isSseContentType,
|
|
6
|
+
isSuccessStatusCode,
|
|
7
|
+
isTextContentType,
|
|
8
|
+
parseJsonContentType
|
|
9
|
+
} from "./is.js";
|
|
10
|
+
import {} from "./options.js";
|
|
11
|
+
function resolveResponses(spec, operationId, operation, responsesConfig) {
|
|
12
|
+
const responses = operation.responses ?? {};
|
|
13
|
+
operation.responses ??= {};
|
|
14
|
+
let foundSuccessResponse = false;
|
|
15
|
+
for (const status in responses) {
|
|
16
|
+
if (status === "default") {
|
|
17
|
+
delete responses[status];
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
operation.responses[status] = structuredClone(
|
|
21
|
+
resolveRef(spec, responses[status])
|
|
22
|
+
);
|
|
23
|
+
if (isSuccessStatusCode(status)) {
|
|
24
|
+
foundSuccessResponse = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!foundSuccessResponse) {
|
|
28
|
+
operation.responses["200"] = {
|
|
29
|
+
description: "OK",
|
|
30
|
+
content: {
|
|
31
|
+
"application/json": {
|
|
32
|
+
schema: {}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
for (const status in operation.responses) {
|
|
38
|
+
const response = operation.responses[status];
|
|
39
|
+
const statusCode = +status;
|
|
40
|
+
const outputName = statusCode !== 200 ? pascalcase(operationId) + status : findUniqueSchemaName(spec, operationId, [
|
|
41
|
+
"output",
|
|
42
|
+
"payload",
|
|
43
|
+
"result"
|
|
44
|
+
]);
|
|
45
|
+
if (!responsesConfig?.flattenErrorResponses) {
|
|
46
|
+
if (!isSuccessStatusCode(status)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (isEmpty(response.content)) {
|
|
51
|
+
response.content = {
|
|
52
|
+
"application/octet-stream": {}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
response["x-response-name"] = outputName;
|
|
56
|
+
for (const [contentType, mediaType] of Object.entries(
|
|
57
|
+
response.content
|
|
58
|
+
)) {
|
|
59
|
+
if (isRef(mediaType.schema)) {
|
|
60
|
+
const { model } = parseRef(mediaType.schema.$ref);
|
|
61
|
+
Object.assign(spec.components.schemas[model], {
|
|
62
|
+
"x-responsebody": true
|
|
63
|
+
// do not assign response ref to a group
|
|
64
|
+
// because they are supposed to be in a separate file only inlined
|
|
65
|
+
// schemas are grouped by operationId
|
|
66
|
+
});
|
|
67
|
+
response["x-response-name"] = model;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (isSseContentType(contentType)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (parseJsonContentType(contentType)) {
|
|
74
|
+
if (isEmpty(mediaType.schema)) {
|
|
75
|
+
spec.components.schemas[outputName] = {
|
|
76
|
+
type: "object",
|
|
77
|
+
additionalProperties: true
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
spec.components.schemas[outputName] = {
|
|
82
|
+
...spec.components.schemas[outputName],
|
|
83
|
+
"x-stream": !isTextContentType(contentType)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
spec.components.schemas[outputName] = {
|
|
87
|
+
...spec.components.schemas[outputName],
|
|
88
|
+
...mediaType.schema,
|
|
89
|
+
"x-responsebody": true,
|
|
90
|
+
"x-response-group": operationId
|
|
91
|
+
};
|
|
92
|
+
operation.responses[status].content[contentType].schema = {
|
|
93
|
+
$ref: `#/components/schemas/${outputName}`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return operation.responses;
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
resolveResponses
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=tune-response.js.map
|