Update package.json and bun.lock to include Rollup plugins, modify build scripts for Rollup integration, and enhance TypeScript configuration for improved module handling. Introduce rollup.config.js for bundling configurations and refactor parser and printer references in tests to align with new structure.

This commit is contained in:
Luke Hagar
2025-09-26 19:05:00 +00:00
parent 34f3cd51bc
commit 5e97d04fb2
14 changed files with 776 additions and 562 deletions

View File

@@ -3,8 +3,8 @@ import plugin from '../src/index';
describe('Custom Extensions Support', () => {
it('should handle custom extensions in top-level keys', () => {
const jsonParser = plugin.parsers?.['openapi-json-parser'];
expect(jsonParser).toBeDefined();
const parser = plugin.parsers?.['openapi-parser'];
expect(parser).toBeDefined();
const testJson = {
'x-custom-field': 'value',
@@ -15,14 +15,14 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonParser?.parse(JSON.stringify(testJson), {});
const result = parser?.parse(JSON.stringify(testJson), { filepath: 'test.json' });
expect(result).toBeDefined();
expect(result?.content).toBeDefined();
});
it('should handle custom extensions in info section', () => {
const jsonParser = plugin.parsers?.['openapi-json-parser'];
expect(jsonParser).toBeDefined();
const parser = plugin.parsers?.['openapi-parser'];
expect(parser).toBeDefined();
const testJson = {
'openapi': '3.0.0',
@@ -36,15 +36,15 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonParser?.parse(JSON.stringify(testJson), {});
const result = parser?.parse(JSON.stringify(testJson), { filepath: 'test.json' });
expect(result).toBeDefined();
expect(result?.content.info).toBeDefined();
expect(result?.content.info['x-api-id']).toBe('api-123');
});
it('should handle custom extensions in operation objects', () => {
const jsonParser = plugin.parsers?.['openapi-json-parser'];
expect(jsonParser).toBeDefined();
const parser = plugin.parsers?.['openapi-parser'];
expect(parser).toBeDefined();
const testJson = {
'openapi': '3.0.0',
@@ -62,14 +62,14 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonParser?.parse(JSON.stringify(testJson), {});
const result = parser?.parse(JSON.stringify(testJson), { filepath: 'test.json' });
expect(result).toBeDefined();
expect(result?.content.paths['/test'].get['x-rate-limit']).toBe(100);
});
it('should handle custom extensions in schema objects', () => {
const jsonParser = plugin.parsers?.['openapi-json-parser'];
expect(jsonParser).toBeDefined();
const parser = plugin.parsers?.['openapi-parser'];
expect(parser).toBeDefined();
const testJson = {
'openapi': '3.0.0',
@@ -89,14 +89,14 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonParser?.parse(JSON.stringify(testJson), {});
const result = parser?.parse(JSON.stringify(testJson), { filepath: 'test.json' });
expect(result).toBeDefined();
expect(result?.content.components.schemas.User['x-custom-type']).toBe('entity');
});
it('should format JSON with custom extensions', () => {
const jsonPrinter = plugin.printers?.['openapi-json-ast'];
expect(jsonPrinter).toBeDefined();
const printer = plugin.printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
content: {
@@ -109,15 +109,15 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here so we don't need to pass a print function
const result = jsonPrinter?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
expect(result).toContain('"x-custom-field"');
expect(result).toContain('"openapi"');
expect(result).toContain('x-custom-field');
expect(result).toContain('openapi');
});
it('should format YAML with custom extensions', () => {
const yamlPrinter = plugin.printers?.['openapi-yaml-ast'];
expect(yamlPrinter).toBeDefined();
const printer = plugin.printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
content: {
@@ -130,15 +130,15 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here so we don't need to pass a print function
const result = yamlPrinter?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
expect(result).toContain('x-custom-field:');
expect(result).toContain('openapi:');
});
it('should handle unknown keys alphabetically at the end', () => {
const jsonParser = plugin.parsers?.['openapi-json-parser'];
expect(jsonParser).toBeDefined();
const parser = plugin.parsers?.['openapi-parser'];
expect(parser).toBeDefined();
const testJson = {
'openapi': '3.0.0',
@@ -149,15 +149,15 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonParser?.parse(JSON.stringify(testJson), {});
const result = parser?.parse(JSON.stringify(testJson), { filepath: 'test.json' });
expect(result).toBeDefined();
expect(result?.content).toBeDefined();
});
describe('Custom extension positioning', () => {
it('should position custom extensions correctly in top-level', () => {
const jsonPrinter = plugin.printers?.['openapi-json-ast'];
expect(jsonPrinter).toBeDefined();
const printer = plugin.printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
content: {
@@ -170,19 +170,21 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonPrinter?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
if (!result) {
throw new Error('Result is undefined');
}
const resultString = result.toString();
// Custom extensions should come after standard keys
const openapiIndex = result.toString().indexOf('"openapi"');
const infoIndex = result.toString().indexOf('"info"');
const pathsIndex = result.toString().indexOf('"paths"');
const xCustomFieldIndex = result.toString().indexOf('"x-custom-field"');
const xMetadataIndex = result.toString().indexOf('"x-metadata"');
const openapiIndex = resultString.indexOf('openapi');
const infoIndex = resultString.indexOf('info');
const pathsIndex = resultString.indexOf('paths');
const xCustomFieldIndex = resultString.indexOf('x-custom-field');
const xMetadataIndex = resultString.indexOf('x-metadata');
expect(openapiIndex).toBeLessThan(infoIndex);
expect(infoIndex).toBeLessThan(pathsIndex);
@@ -191,8 +193,8 @@ describe('Custom Extensions Support', () => {
});
it('should position custom extensions correctly in info section', () => {
const jsonPrinter = plugin.printers?.['openapi-json-ast'];
expect(jsonPrinter).toBeDefined();
const printer = plugin.printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
content: {
@@ -208,19 +210,21 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonPrinter?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
if (!result) {
throw new Error('Result is undefined');
}
const resultString = result.toString();
// Custom extensions should come after standard keys
const titleIndex = result.toString().indexOf('"title"');
const descriptionIndex = result.toString().indexOf('"description"');
const versionIndex = result.toString().indexOf('"version"');
const xApiIdIndex = result.toString().indexOf('"x-api-id"');
const xVersionInfoIndex = result.toString().indexOf('"x-version-info"');
const titleIndex = resultString.indexOf('title');
const descriptionIndex = resultString.indexOf('description');
const versionIndex = resultString.indexOf('version');
const xApiIdIndex = resultString.indexOf('x-api-id');
const xVersionInfoIndex = resultString.indexOf('x-version-info');
expect(titleIndex).toBeLessThan(versionIndex);
expect(versionIndex).toBeLessThan(descriptionIndex);
@@ -229,8 +233,8 @@ describe('Custom Extensions Support', () => {
});
it('should position custom extensions correctly in operation objects', () => {
const jsonPrinter = plugin.printers?.['openapi-json-ast'];
expect(jsonPrinter).toBeDefined();
const printer = plugin.printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
content: {
@@ -250,24 +254,19 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonPrinter?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
if (!result) {
throw new Error('Result is undefined');
}
const resultString = result.toString();
// Custom extensions should come after standard keys
// Find the operation section specifically
const operationStart = result.toString().indexOf('"get": {');
// Find the end of the operation object
const operationEnd = result.toString().indexOf('}', result.toString().lastIndexOf('"x-custom-auth"'));
const operationSection = result.toString().substring(operationStart, operationEnd + 1);
const summaryIndex = operationSection.indexOf('"summary"');
const responsesIndex = operationSection.indexOf('"responses"');
const xRateLimitIndex = operationSection.indexOf('"x-rate-limit"');
const xCustomAuthIndex = operationSection.indexOf('"x-custom-auth"');
const summaryIndex = resultString.indexOf('summary');
const responsesIndex = resultString.indexOf('responses');
const xRateLimitIndex = resultString.indexOf('x-rate-limit');
const xCustomAuthIndex = resultString.indexOf('x-custom-auth');
expect(summaryIndex).toBeLessThan(responsesIndex);
expect(responsesIndex).toBeLessThan(xCustomAuthIndex);
@@ -275,8 +274,8 @@ describe('Custom Extensions Support', () => {
});
it('should position custom extensions correctly in schema objects', () => {
const jsonPrinter = plugin.printers?.['openapi-json-ast'];
expect(jsonPrinter).toBeDefined();
const printer = plugin.printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
content: {
@@ -296,18 +295,20 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonPrinter?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
if (!result) {
throw new Error('Result is undefined');
}
const resultString = result.toString();
// Custom extensions should come after standard keys
const typeIndex = result.toString().indexOf('"type"');
const propertiesIndex = result.toString().indexOf('"properties"');
const xCustomTypeIndex = result.toString().indexOf('"x-custom-type"');
const xValidationRulesIndex = result.toString().indexOf('"x-validation-rules"');
const typeIndex = resultString.indexOf('type');
const propertiesIndex = resultString.indexOf('properties');
const xCustomTypeIndex = resultString.indexOf('x-custom-type');
const xValidationRulesIndex = resultString.indexOf('x-validation-rules');
expect(typeIndex).toBeLessThan(propertiesIndex);
expect(propertiesIndex).toBeLessThan(xCustomTypeIndex);
@@ -317,8 +318,8 @@ describe('Custom Extensions Support', () => {
describe('Unknown key handling', () => {
it('should sort unknown keys alphabetically at the end', () => {
const jsonPrinter = plugin.printers?.['openapi-json-ast'];
expect(jsonPrinter).toBeDefined();
const printer = plugin.printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
content: {
@@ -331,19 +332,21 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonPrinter?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
if (!result) {
throw new Error('Result is undefined');
}
const resultString = result.toString();
// Unknown keys should come after standard keys and be sorted alphabetically
const openapiIndex = result.toString().indexOf('"openapi"');
const infoIndex = result.toString().indexOf('"info"');
const pathsIndex = result.toString().indexOf('"paths"');
const anotherUnknownIndex = result.toString().indexOf('"another-unknown"');
const unknownFieldIndex = result.toString().indexOf('"unknown-field"');
const openapiIndex = resultString.indexOf('openapi');
const infoIndex = resultString.indexOf('info');
const pathsIndex = resultString.indexOf('paths');
const anotherUnknownIndex = resultString.indexOf('another-unknown');
const unknownFieldIndex = resultString.indexOf('unknown-field');
expect(openapiIndex).toBeLessThan(infoIndex);
expect(infoIndex).toBeLessThan(pathsIndex);
@@ -355,8 +358,8 @@ describe('Custom Extensions Support', () => {
});
it('should handle mixed custom extensions and unknown keys', () => {
const jsonPrinter = plugin.printers?.['openapi-json-ast'];
expect(jsonPrinter).toBeDefined();
const printer = plugin.printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
content: {
@@ -371,21 +374,23 @@ describe('Custom Extensions Support', () => {
};
// @ts-expect-error We are mocking things here
const result = jsonPrinter?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
if (!result) {
throw new Error('Result is undefined');
}
const resultString = result.toString();
// Standard keys first, then custom extensions, then unknown keys alphabetically
const openapiIndex = result.toString().indexOf('"openapi"');
const infoIndex = result.toString().indexOf('"info"');
const pathsIndex = result.toString().indexOf('"paths"');
const xCustomFieldIndex = result.toString().indexOf('"x-custom-field"');
const xMetadataIndex = result.toString().indexOf('"x-metadata"');
const anotherUnknownIndex = result.toString().indexOf('"another-unknown"');
const unknownFieldIndex = result.toString().indexOf('"unknown-field"');
const openapiIndex = resultString.indexOf('openapi');
const infoIndex = resultString.indexOf('info');
const pathsIndex = resultString.indexOf('paths');
const xCustomFieldIndex = resultString.indexOf('x-custom-field');
const xMetadataIndex = resultString.indexOf('x-metadata');
const anotherUnknownIndex = resultString.indexOf('another-unknown');
const unknownFieldIndex = resultString.indexOf('unknown-field');
expect(openapiIndex).toBeLessThan(infoIndex);
expect(infoIndex).toBeLessThan(pathsIndex);