Update pretest script in package.json to use bun for building. Refactor sorting logic in index.ts for OpenAPI keys, enhancing clarity and performance. Clean up test files by removing unnecessary console logs and ensuring consistent formatting.

This commit is contained in:
Luke Hagar
2025-09-28 22:50:24 +00:00
parent 6226184808
commit 6378848afd
6 changed files with 116 additions and 69 deletions

View File

@@ -38,7 +38,7 @@
"scripts": {
"build": "rollup -c && tsc --emitDeclarationOnly",
"dev": "rollup -c --watch",
"pretest": "rollup -c",
"pretest": "bun run build",
"test": "bun test",
"test:coverage": "bun test --coverage",
"test:watch": "bun test --watch",
@@ -86,4 +86,4 @@
"@types/js-yaml": "^4.0.0",
"js-yaml": "^4.1.0"
}
}
}

View File

@@ -300,10 +300,9 @@ function sortOpenAPIKeys(obj: any): any {
const standardKeys = getStandardKeysForContext(contextKey);
const customExtensions = vendorExtensions[contextKey] || {};
const sortedKeys = Object.keys(obj).sort((a, b) => {
// Use the unified sorting function
return sortKeys(a, b, standardKeys, customExtensions);
return sortKeys(a, b, standardKeys, customExtensions);;
});
const sortedObj: any = {};
@@ -515,39 +514,52 @@ function sortKeys(a: string, b: string, standardKeys: readonly string[], customE
const aCustomPos = customExtensions[a];
const bCustomPos = customExtensions[b];
// Handle custom extensions first
// Get standard key positions
const aStandardIndex = standardKeys.indexOf(a);
const bStandardIndex = standardKeys.indexOf(b);
// Both are custom extensions
if (aCustomPos !== undefined && bCustomPos !== undefined) {
return aCustomPos - bCustomPos;
}
if (aCustomPos !== undefined) {
if (aCustomPos < standardKeys.length) {
return -1; // Custom key should come before standard keys
// Both are standard keys
if (aStandardIndex !== -1 && bStandardIndex !== -1) {
return aStandardIndex - bStandardIndex;
}
// One is custom, one is standard
if (aCustomPos !== undefined && bStandardIndex !== -1) {
// Custom key should be positioned relative to standard keys
if (aCustomPos < bStandardIndex) {
return -1; // Custom key comes before this standard key
} else if (aCustomPos > bStandardIndex) {
return 1; // Custom key comes after this standard key
} else {
return -1; // Custom key comes before standard key at same position
}
}
if (bCustomPos !== undefined) {
if (bCustomPos < standardKeys.length) {
return 1; // Custom key should come before standard keys
if (bCustomPos !== undefined && aStandardIndex !== -1) {
// Custom key should be positioned relative to standard keys
if (bCustomPos < aStandardIndex) {
return 1; // Custom key comes before this standard key
} else if (bCustomPos > aStandardIndex) {
return -1; // Custom key comes after this standard key
} else {
return 1; // Standard key comes after custom key at same position
}
}
// Standard sorting
const aIndex = standardKeys.indexOf(a);
const bIndex = standardKeys.indexOf(b);
// One is standard, one is unknown
if (aStandardIndex !== -1) return -1; // Standard key comes first
if (bStandardIndex !== -1) return 1; // Standard key comes first
if (aIndex !== -1 && bIndex !== -1) {
return aIndex - bIndex;
}
// One is custom, one is unknown
if (aCustomPos !== undefined) return -1; // Custom key comes before unknown
if (bCustomPos !== undefined) return 1; // Custom key comes before unknown
if (aIndex !== -1) return -1;
if (bIndex !== -1) return 1;
// Handle custom extensions after standard keys
if (aCustomPos !== undefined) return -1;
if (bCustomPos !== undefined) return 1;
// For unknown keys, sort alphabetically at the end
// Both are unknown - sort alphabetically
return a.localeCompare(b);
}
//#endregion

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'bun:test';
import {parsers, printers} from '../src/index';
import { parsers, printers } from '../src/index';
describe('Custom Extensions Support', () => {
it('should handle custom extensions in top-level keys', () => {
@@ -110,7 +110,7 @@ describe('Custom Extensions Support', () => {
}
};
// @ts-expect-error We are mocking things here so we don't need to pass a print function
// @ts-expect-error We are mocking things here so we don't need to pass a print function
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
expect(result).toContain('x-custom-field');
@@ -175,7 +175,7 @@ describe('Custom Extensions Support', () => {
}
};
// @ts-expect-error We are mocking things here
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
@@ -184,7 +184,7 @@ describe('Custom Extensions Support', () => {
}
const resultString = result.toString();
// Custom extensions should come after standard keys
const openapiIndex = resultString.indexOf('openapi');
const infoIndex = resultString.indexOf('info');
@@ -217,7 +217,7 @@ describe('Custom Extensions Support', () => {
}
};
// @ts-expect-error We are mocking things here
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
@@ -263,7 +263,7 @@ describe('Custom Extensions Support', () => {
}
};
// @ts-expect-error We are mocking things here
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
@@ -272,7 +272,7 @@ describe('Custom Extensions Support', () => {
}
const resultString = result.toString();
const summaryIndex = resultString.indexOf('summary');
const responsesIndex = resultString.indexOf('responses');
const xRateLimitIndex = resultString.indexOf('x-rate-limit');
@@ -306,7 +306,7 @@ describe('Custom Extensions Support', () => {
}
};
// @ts-expect-error We are mocking things here
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
@@ -345,7 +345,7 @@ describe('Custom Extensions Support', () => {
}
};
// @ts-expect-error We are mocking things here
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
@@ -371,6 +371,45 @@ describe('Custom Extensions Support', () => {
expect(anotherUnknownIndex).toBeLessThan(unknownFieldIndex);
});
it('should handle specific extension placement', () => {
const printer = printers?.['openapi-ast'];
expect(printer).toBeDefined();
const testData = {
isOpenAPI: true,
format: 'yaml',
content: {
'info': { 'title': 'Test API', 'version': '1.0.0' },
'openapi': '3.0.0',
'x-tagGroups': 'value',
'tags': 'value',
'paths': {},
'x-metadata': { 'custom': 'data' },
}
};
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => 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 = resultString.indexOf('openapi');
const infoIndex = resultString.indexOf('info');
const pathsIndex = resultString.indexOf('paths');
const xTagGroupsIndex = resultString.indexOf('x-tagGroups:');
const tagsIndex = resultString.indexOf('tags:');
expect(openapiIndex).toBeLessThan(infoIndex);
expect(infoIndex).toBeLessThan(pathsIndex);
expect(tagsIndex).toBeLessThan(xTagGroupsIndex);
});
it('should handle mixed custom extensions and unknown keys', () => {
const printer = printers?.['openapi-ast'];
expect(printer).toBeDefined();
@@ -389,7 +428,7 @@ describe('Custom Extensions Support', () => {
}
};
// @ts-expect-error We are mocking things here
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
@@ -398,7 +437,7 @@ describe('Custom Extensions Support', () => {
}
const resultString = result.toString();
// Standard keys first, then custom extensions, then unknown keys alphabetically
const openapiIndex = resultString.indexOf('openapi');
const infoIndex = resultString.indexOf('info');

View File

@@ -140,8 +140,6 @@ describe('Key Ordering Tests', () => {
throw new Error('Result is undefined');
}
console.log('result', result);
const resultString = result.toString();
const testIndex = resultString.indexOf('test"');
@@ -198,7 +196,6 @@ describe('Key Ordering Tests', () => {
// @ts-expect-error We are mocking things here so we don't need to pass a print function
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 });
console.log('result', result);
expect(result).toBeDefined();
if (!result) {

View File

@@ -1,11 +1,11 @@
import { describe, expect, it } from 'bun:test';
import plugin from '../dist/index.js';
import { parsers, printers } from '../src/index.js';
describe('Prettier OpenAPI Plugin', () => {
it('should format OpenAPI JSON files', () => {
const parser = plugin.parsers?.['openapi-parser'];
const printer = plugin.printers?.['openapi-ast'];
const parser = parsers?.['openapi-parser'];
const printer = printers?.['openapi-ast'];
expect(parser).toBeDefined();
expect(printer).toBeDefined();
@@ -39,7 +39,7 @@ describe('Prettier OpenAPI Plugin', () => {
// Format the parsed content
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => parsed }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
expect(result).toContain('"openapi"');
expect(result).toContain('"info"');
@@ -53,15 +53,15 @@ describe('Prettier OpenAPI Plugin', () => {
const openapiIndex = result.toString().indexOf('"openapi"');
const infoIndex = result.toString().indexOf('"info"');
const pathsIndex = result.toString().indexOf('"paths"');
expect(openapiIndex).toBeLessThan(infoIndex);
expect(infoIndex).toBeLessThan(pathsIndex);
});
it('should format OpenAPI YAML files', () => {
const parser = plugin.parsers?.['openapi-parser'];
const printer = plugin.printers?.['openapi-ast'];
const parser = parsers?.['openapi-parser'];
const printer = printers?.['openapi-ast'];
expect(parser).toBeDefined();
expect(printer).toBeDefined();
@@ -87,12 +87,12 @@ openapi: 3.0.0`;
// Format the parsed content
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => parsed }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
expect(result).toContain('openapi:');
expect(result).toContain('info:');
expect(result).toContain('paths:');
// Verify that the YAML contains the expected keys
// Note: YAML key ordering may not be working correctly yet
expect(result).toContain('openapi:');
@@ -102,21 +102,21 @@ openapi: 3.0.0`;
if (!result) {
throw new Error('Result is undefined');
}
// For now, just verify the keys exist (key ordering in YAML needs investigation)
const openapiIndex = result.toString().indexOf('openapi:');
const infoIndex = result.toString().indexOf('info:');
const pathsIndex = result.toString().indexOf('paths:');
expect(openapiIndex).toBeGreaterThanOrEqual(0);
expect(infoIndex).toBeGreaterThanOrEqual(0);
expect(pathsIndex).toBeGreaterThanOrEqual(0);
});
it('should format Swagger 2.0 JSON files', () => {
const parser = plugin.parsers?.['openapi-parser'];
const printer = plugin.printers?.['openapi-ast'];
const parser = parsers?.['openapi-parser'];
const printer = printers?.['openapi-ast'];
expect(parser).toBeDefined();
expect(printer).toBeDefined();
@@ -155,7 +155,7 @@ openapi: 3.0.0`;
// Format the parsed content
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => parsed }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
expect(result).toContain('"swagger"');
expect(result).toContain('"info"');
@@ -165,13 +165,13 @@ openapi: 3.0.0`;
if (!result) {
throw new Error('Result is undefined');
}
// Verify correct Swagger 2.0 key ordering
const swaggerIndex = result.toString().indexOf('"swagger"');
const infoIndex = result.toString().indexOf('"info"');
const pathsIndex = result.toString().indexOf('"paths"');
const definitionsIndex = result.toString().indexOf('"definitions"');
expect(swaggerIndex).toBeLessThan(infoIndex);
expect(infoIndex).toBeLessThan(pathsIndex);
expect(pathsIndex).toBeLessThan(definitionsIndex);
@@ -181,9 +181,9 @@ openapi: 3.0.0`;
describe('Key Ordering Tests', () => {
describe('Top-level key ordering', () => {
it('should sort OpenAPI 3.0+ keys correctly', () => {
const parser = plugin.parsers?.['openapi-parser'];
const printer = plugin.printers?.['openapi-ast'];
const parser = parsers?.['openapi-parser'];
const printer = printers?.['openapi-ast'];
expect(parser).toBeDefined();
expect(printer).toBeDefined();
@@ -233,9 +233,9 @@ describe('Key Ordering Tests', () => {
});
it('should sort Swagger 2.0 keys correctly', () => {
const parser = plugin.parsers?.['openapi-parser'];
const printer = plugin.printers?.['openapi-ast'];
const parser = parsers?.['openapi-parser'];
const printer = printers?.['openapi-ast'];
expect(parser).toBeDefined();
expect(printer).toBeDefined();

View File

@@ -23,7 +23,7 @@ describe('Simple Key Ordering Tests', () => {
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
expect(result).toBeDefined();
if (!result) {
throw new Error('Result is undefined');
}
@@ -86,7 +86,7 @@ describe('Simple Key Ordering Tests', () => {
}
const resultString = result.toString();
// Check that operation keys appear in the correct order
const summaryIndex = resultString.indexOf('summary');
const operationIdIndex = resultString.indexOf('operationId');
@@ -141,7 +141,7 @@ describe('Simple Key Ordering Tests', () => {
}
const resultString = result.toString();
// Check that info keys appear in the correct order
const titleIndex = resultString.indexOf('title');
const versionIndex = resultString.indexOf('version');
@@ -175,13 +175,12 @@ describe('Simple Key Ordering Tests', () => {
// @ts-expect-error We are mocking things here
const result = printer?.print({ getNode: () => testData }, { tabWidth: 2 }, () => '');
console.log('result', result);
expect(result).toBeDefined();
if (!result) {
throw new Error('Result is undefined');
}
// Custom extensions should come after standard keys
const openapiIndex = result.toString().indexOf('openapi');
const infoIndex = result.toString().indexOf('info');