Files
prettier-plugin-openapi/CUSTOMIZATION.md
2025-09-25 01:36:23 +00:00

11 KiB

Customizing Key Ordering

This document explains how to customize the key ordering in the Prettier OpenAPI plugin.

Overview

The plugin uses configuration arrays and maps at the top of the src/index.ts file to determine the order of keys in OpenAPI/Swagger files. You can easily modify these arrays to change the sorting behavior.

Configuration Arrays

All key ordering configuration is located at the top of src/index.ts in the "KEY ORDERING CONFIGURATION" section.

Top-Level Keys

const TOP_LEVEL_KEYS = [
  'openapi',
  'info',
  'servers',
  'paths',
  'components',
  'security',
  'tags',
  'externalDocs',
] as const;

Info Section Keys

const INFO_KEYS = [
  'title',
  'description',
  'version',
  'termsOfService',
  'contact',
  'license',
] as const;

Contact Section Keys

const CONTACT_KEYS = [
  'name',
  'url',
  'email',
] as const;

License Section Keys

const LICENSE_KEYS = [
  'name',
  'url',
] as const;

Components Section Keys

const COMPONENTS_KEYS = [
  'schemas',
  'responses',
  'parameters',
  'examples',
  'requestBodies',
  'headers',
  'securitySchemes',
  'links',
  'callbacks',
] as const;

Operation Keys

const OPERATION_KEYS = [
  'tags',
  'summary',
  'description',
  'operationId',
  'parameters',
  'requestBody',
  'responses',
  'callbacks',
  'deprecated',
  'security',
  'servers',
] as const;

Parameter Keys

const PARAMETER_KEYS = [
  'name',
  'in',
  'description',
  'required',
  'deprecated',
  'allowEmptyValue',
  'style',
  'explode',
  'allowReserved',
  'schema',
  'example',
  'examples',
] as const;

Schema Keys

const SCHEMA_KEYS = [
  'type',
  'format',
  'title',
  'description',
  'default',
  'example',
  'examples',
  'enum',
  'const',
  'multipleOf',
  'maximum',
  'exclusiveMaximum',
  'minimum',
  'exclusiveMinimum',
  'maxLength',
  'minLength',
  'pattern',
  'maxItems',
  'minItems',
  'uniqueItems',
  'maxProperties',
  'minProperties',
  'required',
  'properties',
  'patternProperties',
  'additionalProperties',
  'items',
  'allOf',
  'oneOf',
  'anyOf',
  'not',
  'discriminator',
  'xml',
  'externalDocs',
  'deprecated',
] as const;

Response Keys

const RESPONSE_KEYS = [
  'description',
  'headers',
  'content',
  'links',
] as const;

Security Scheme Keys

const SECURITY_SCHEME_KEYS = [
  'type',
  'description',
  'name',
  'in',
  'scheme',
  'bearerFormat',
  'flows',
  'openIdConnectUrl',
] as const;

OAuth Flow Keys

const OAUTH_FLOW_KEYS = [
  'authorizationUrl',
  'tokenUrl',
  'refreshUrl',
  'scopes',
] as const;

Server Keys

const SERVER_KEYS = [
  'url',
  'description',
  'variables',
] as const;

Server Variable Keys

const SERVER_VARIABLE_KEYS = [
  'enum',
  'default',
  'description',
] as const;

Tag Keys

const TAG_KEYS = [
  'name',
  'description',
  'externalDocs',
] as const;

External Docs Keys

const EXTERNAL_DOCS_KEYS = [
  'description',
  'url',
] as const;

How to Customize

1. Reorder Keys

To change the order of keys, simply rearrange the arrays:

// Example: Put 'description' before 'title' in info section
const INFO_KEYS = [
  'description',  // Moved to first
  'title',
  'version',
  'termsOfService',
  'contact',
  'license',
] as const;

2. Add New Keys

To add support for new keys, add them to the appropriate array:

// Example: Add custom keys to info section
const INFO_KEYS = [
  'title',
  'description',
  'version',
  'customField',  // New key
  'termsOfService',
  'contact',
  'license',
] as const;

3. Remove Keys

To remove keys from sorting (they'll be sorted alphabetically), simply remove them from the arrays:

// Example: Remove 'termsOfService' from info section
const INFO_KEYS = [
  'title',
  'description',
  'version',
  // 'termsOfService',  // Removed
  'contact',
  'license',
] as const;

4. Create Custom Ordering

You can create completely custom ordering by modifying the arrays:

// Example: Custom ordering for your organization's standards
const INFO_KEYS = [
  'title',
  'version',
  'description',
  'contact',
  'license',
  'termsOfService',
] as const;

Special Sorting Rules

Some sections have special sorting rules that can't be changed by modifying arrays:

  • Paths: Sorted by specificity (more specific paths first)
  • Response Codes: Sorted numerically (200, 201, 400, 404, etc.)
  • Schema Properties: Sorted alphabetically
  • Parameters: Sorted alphabetically
  • Security Schemes: Sorted alphabetically

Testing Changes

After modifying the configuration arrays:

  1. Build the plugin:

    bun run build
    
  2. Run tests to ensure nothing is broken:

    bun test
    
  3. Test with your OpenAPI files:

    npx prettier --write your-api.yaml
    

Examples

Example 1: Prioritize Security

const TOP_LEVEL_KEYS = [
  'openapi',
  'info',
  'security',  // Moved up
  'servers',
  'paths',
  'components',
  'tags',
  'externalDocs',
] as const;

Example 2: Custom Info Ordering

const INFO_KEYS = [
  'title',
  'version',
  'description',
  'contact',
  'license',
  'termsOfService',
] as const;

Example 3: Schema-First Components

const COMPONENTS_KEYS = [
  'schemas',  // Already first, but emphasizing
  'responses',
  'parameters',
  'examples',
  'requestBodies',
  'headers',
  'securitySchemes',
  'links',
  'callbacks',
] as const;

Custom Extensions

The plugin supports custom extensions (keys starting with x-) with configurable positioning. You can specify exactly where your custom extensions should appear in the sorted output.

Configuration

Custom extensions are configured at the top of src/index.ts in the "CUSTOM EXTENSION CONFIGURATION" section:

// Custom extensions for top-level OpenAPI keys
const CUSTOM_TOP_LEVEL_EXTENSIONS: Record<string, number> = {
  'x-custom-field': 2, // Will be placed after 'info' (position 1)
  'x-api-version': 0,  // Will be placed before 'openapi'
};

// Custom extensions for info section
const CUSTOM_INFO_EXTENSIONS: Record<string, number> = {
  'x-api-id': 1,      // Will be placed after 'title' (position 0)
  'x-version-info': 3, // Will be placed after 'version' (position 2)
};

How Positioning Works

  • Position 0: Before the first standard key
  • Position 1: After the first standard key
  • Position 2: After the second standard key
  • Position N: After the Nth standard key
  • Position > standard keys length: After all standard keys

Examples

Example 1: Top-Level Custom Extensions

const CUSTOM_TOP_LEVEL_EXTENSIONS: Record<string, number> = {
  'x-api-version': 0,     // Before 'openapi'
  'x-custom-field': 2,    // After 'info' (position 1)
  'x-metadata': 8,        // After all standard keys
};

Result:

x-api-version: "1.0"
openapi: 3.0.0
info: ...
x-custom-field: "value"
servers: ...
paths: ...
components: ...
x-metadata: {...}

Example 2: Info Section Custom Extensions

const CUSTOM_INFO_EXTENSIONS: Record<string, number> = {
  'x-api-id': 1,          // After 'title'
  'x-version-info': 3,    // After 'version'
  'x-custom-info': 6,     // After all standard keys
};

Result:

info:
  title: My API
  x-api-id: "api-123"
  description: API Description
  version: 1.0.0
  x-version-info: "v1.0.0-beta"
  contact: ...
  license: ...
  x-custom-info: {...}

Example 3: Operation Custom Extensions

const CUSTOM_OPERATION_EXTENSIONS: Record<string, number> = {
  'x-rate-limit': 5,      // After 'parameters' (position 4)
  'x-custom-auth': 10,    // After 'servers' (position 9)
};

Result:

get:
  tags: [...]
  summary: ...
  description: ...
  operationId: ...
  parameters: [...]
  x-rate-limit: 100
  requestBody: ...
  responses: ...
  callbacks: ...
  deprecated: false
  security: [...]
  servers: [...]
  x-custom-auth: "bearer"

Available Extension Contexts

Context Configuration Object Description
top-level CUSTOM_TOP_LEVEL_EXTENSIONS Root OpenAPI object
info CUSTOM_INFO_EXTENSIONS Info section
components CUSTOM_COMPONENTS_EXTENSIONS Components section
operation CUSTOM_OPERATION_EXTENSIONS HTTP operation objects
parameter CUSTOM_PARAMETER_EXTENSIONS Parameter objects
schema CUSTOM_SCHEMA_EXTENSIONS Schema objects
response CUSTOM_RESPONSE_EXTENSIONS Response objects
securityScheme CUSTOM_SECURITY_SCHEME_EXTENSIONS Security scheme objects
server CUSTOM_SERVER_EXTENSIONS Server objects
tag CUSTOM_TAG_EXTENSIONS Tag objects
externalDocs CUSTOM_EXTERNAL_DOCS_EXTENSIONS External docs objects

Unknown Keys Behavior

Keys that are not in the standard arrays or custom extensions configuration will be sorted alphabetically at the bottom of their respective objects.

Example:

info:
  title: My API
  version: 1.0.0
  # Standard keys in order
  contact: ...
  license: ...
  # Custom extensions in configured order
  x-api-id: "api-123"
  # Unknown keys sorted alphabetically at the end
  unknown-field: "value"
  x-other-extension: "value"

Complete Example

Here's a complete example of custom extension configuration:

// Top-level custom extensions
const CUSTOM_TOP_LEVEL_EXTENSIONS: Record<string, number> = {
  'x-api-version': 0,     // Before 'openapi'
  'x-custom-field': 2,    // After 'info'
  'x-metadata': 8,        // After all standard keys
};

// Info section custom extensions
const CUSTOM_INFO_EXTENSIONS: Record<string, number> = {
  'x-api-id': 1,          // After 'title'
  'x-version-info': 3,    // After 'version'
};

// Operation custom extensions
const CUSTOM_OPERATION_EXTENSIONS: Record<string, number> = {
  'x-rate-limit': 5,      // After 'parameters'
  'x-custom-auth': 10,    // After 'servers'
};

// Schema custom extensions
const CUSTOM_SCHEMA_EXTENSIONS: Record<string, number> = {
  'x-custom-type': 0,      // Before 'type'
  'x-validation-rules': 30, // After 'deprecated'
};

Notes

  • Keys not in the configuration arrays will be sorted alphabetically
  • Custom extensions can be positioned anywhere in the key order
  • Unknown keys (not in standard or custom lists) default to alphabetical sorting at the bottom
  • The as const assertion ensures type safety
  • Changes require rebuilding the plugin (bun run build)
  • Test your changes with real OpenAPI files to ensure they work as expected