{"_id":"@api-extractor-tools/declaration-file-normalizer","_rev":"6-f6b51e22855593c5a0ca6f7468604ade","name":"@api-extractor-tools/declaration-file-normalizer","dist-tags":{"alpha":"0.0.1-alpha.2","latest":"0.1.0"},"versions":{"0.0.1-alpha.2":{"name":"@api-extractor-tools/declaration-file-normalizer","version":"0.0.1-alpha.2","keywords":[],"author":"","license":"MIT","_id":"@api-extractor-tools/declaration-file-normalizer@0.0.1-alpha.2","maintainers":[{"name":"northm","email":"michael.l.north@gmail.com"}],"bin":{"declaration-file-normalizer":"dist/cli.js"},"dist":{"shasum":"59364def50c9c98bae2bc667dd87a9ed046af7fb","tarball":"https://registry.npmjs.org/@api-extractor-tools/declaration-file-normalizer/-/declaration-file-normalizer-0.0.1-alpha.2.tgz","fileCount":49,"integrity":"sha512-M3CYuja3c7Sz2GIOozafZ7NH0N835nbEzSPx4Ef2iS/qmjVKMoXl8Q/7Nu3HcoqyPwo31YlZdKClBTtwwWPEPQ==","signatures":[{"sig":"MEYCIQCGgVAx09/wRwljvcGgP3tEzdpqTeopODERLB/LxpR55QIhAKXRtJgkjeL/4rQx0Z5nsjAkXc7yPnOulyjoouRkz6WR","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":154241},"main":"dist/index.js","type":"module","_from":"file:api-extractor-tools-declaration-file-normalizer-0.0.1-alpha.2.tgz","types":"dist/declaration-file-normalizer-public.d.ts","scripts":{"test":"vitest run","build":"tsc && node dist/cli.js dist/index.d.ts && api-extractor run --local","check":"pnpm check:eslint && pnpm check:typecheck-tests && pnpm check:api-report","clean":"rm -rf dist","check:eslint":"eslint src test","test:coverage":"vitest run --coverage","check:api-report":"api-extractor run","generate:api-report":"api-extractor run --local --verbose","check:typecheck-tests":"tsc -p test/tsconfig.json"},"_npmUser":{"name":"northm","email":"michael.l.north@gmail.com"},"_resolved":"/tmp/bb5e68f7c14d2add72f2de1190ceba1d/api-extractor-tools-declaration-file-normalizer-0.0.1-alpha.2.tgz","_integrity":"sha512-M3CYuja3c7Sz2GIOozafZ7NH0N835nbEzSPx4Ef2iS/qmjVKMoXl8Q/7Nu3HcoqyPwo31YlZdKClBTtwwWPEPQ==","_npmVersion":"10.8.2","description":"Normalizes TypeScript declaration files","directories":{},"_nodeVersion":"20.19.6","dependencies":{"typescript":"5.8.3"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.15","@types/node":"^22.10.2","@vitest/coverage-v8":"^4.0.15","@microsoft/api-extractor":"^7.55.1"},"_npmOperationalInternal":{"tmp":"tmp/declaration-file-normalizer_0.0.1-alpha.2_1767304041395_0.6837823648196044","host":"s3://npm-registry-packages-npm-production"}},"0.1.0-alpha.3":{"name":"@api-extractor-tools/declaration-file-normalizer","version":"0.1.0-alpha.3","keywords":[],"author":"","license":"MIT","_id":"@api-extractor-tools/declaration-file-normalizer@0.1.0-alpha.3","maintainers":[{"name":"northm","email":"michael.l.north@gmail.com"}],"bin":{"declaration-file-normalizer":"dist/cli.js"},"dist":{"shasum":"bdd07acf958dbcde7c0892e50c090bfbb6d445ee","tarball":"https://registry.npmjs.org/@api-extractor-tools/declaration-file-normalizer/-/declaration-file-normalizer-0.1.0-alpha.3.tgz","fileCount":49,"integrity":"sha512-oTCm9Cf5D6SRCDP4aM2OQEUempMo4HZTuoh1z5lQXJFc5D3Br4CDLdz4kNvWaOre5xLWJZTjeslpsvoxiG3xtg==","signatures":[{"sig":"MEQCIDq0xDJvTS924YKC20mOyyRj1WAOEnXmeaptONWlYgQ6AiB/lNPbY+YRfnSZQj86N3zuak1QupEEBS3PWn66XVFrbg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":178633},"main":"dist/index.js","type":"module","_from":"file:api-extractor-tools-declaration-file-normalizer-0.1.0-alpha.3.tgz","types":"dist/declaration-file-normalizer-public.d.ts","scripts":{"test":"vitest run","build":"tsc && node dist/cli.js dist/index.d.ts && api-extractor run --local","check":"pnpm check:eslint && pnpm check:typecheck-tests && pnpm check:api-report","clean":"rm -rf dist","check:eslint":"eslint src test","test:coverage":"vitest run --coverage","check:api-report":"api-extractor run","generate:api-report":"api-extractor run --local --verbose","check:typecheck-tests":"tsc -p test/tsconfig.json"},"_npmUser":{"name":"northm","email":"michael.l.north@gmail.com"},"_resolved":"/tmp/1b90f73dc9b9dc3804b63a6bd1e2fef0/api-extractor-tools-declaration-file-normalizer-0.1.0-alpha.3.tgz","_integrity":"sha512-oTCm9Cf5D6SRCDP4aM2OQEUempMo4HZTuoh1z5lQXJFc5D3Br4CDLdz4kNvWaOre5xLWJZTjeslpsvoxiG3xtg==","_npmVersion":"10.8.2","description":"Normalizes TypeScript declaration files","directories":{},"_nodeVersion":"20.19.6","dependencies":{"typescript":"5.8.3"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.15","@types/node":"^22.10.2","@vitest/coverage-v8":"^4.0.15","@microsoft/api-extractor":"^7.55.1"},"_npmOperationalInternal":{"tmp":"tmp/declaration-file-normalizer_0.1.0-alpha.3_1767564735306_0.4999519849740832","host":"s3://npm-registry-packages-npm-production"}},"0.1.0-alpha.4":{"name":"@api-extractor-tools/declaration-file-normalizer","version":"0.1.0-alpha.4","keywords":[],"author":"","license":"MIT","_id":"@api-extractor-tools/declaration-file-normalizer@0.1.0-alpha.4","maintainers":[{"name":"northm","email":"michael.l.north@gmail.com"}],"bin":{"declaration-file-normalizer":"dist/cli.js"},"dist":{"shasum":"d4acfbc5ac16bb42d98427613ab5e6fe4651578d","tarball":"https://registry.npmjs.org/@api-extractor-tools/declaration-file-normalizer/-/declaration-file-normalizer-0.1.0-alpha.4.tgz","fileCount":47,"integrity":"sha512-a9gutMF0kN6Paxc9xp9inij5eyn5D0w1zBiV35jfoRwD2yYF3QSp1hEookMU5sd6Q6Pt6RpSrl4Cf9KEfme8rg==","signatures":[{"sig":"MEUCIHmypwmwRoeK3a+fd7uj7CAHIPKwi/D/sg+Qg0ym/W0ZAiEA3Lbes0mclfCfuk6/Smcq2uwQQnytwuwJ4Yk0e32P8KQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":187279},"main":"dist/index.js","type":"module","_from":"file:api-extractor-tools-declaration-file-normalizer-0.1.0-alpha.4.tgz","types":"dist/declaration-file-normalizer-public.d.ts","scripts":{"test":"vitest run","build":"tsc && node dist/cli.js dist/index.d.ts && api-extractor run --local","check":"pnpm check:eslint && pnpm check:typecheck-tests && pnpm check:api-report","clean":"rm -rf dist","check:eslint":"eslint src test","test:coverage":"vitest run --coverage","check:api-report":"api-extractor run","generate:api-report":"api-extractor run --local --verbose","check:typecheck-tests":"tsc -p test/tsconfig.json"},"_npmUser":{"name":"northm","email":"michael.l.north@gmail.com"},"_resolved":"/tmp/901936fb6600f4d70c93abde8fd99ad4/api-extractor-tools-declaration-file-normalizer-0.1.0-alpha.4.tgz","_integrity":"sha512-a9gutMF0kN6Paxc9xp9inij5eyn5D0w1zBiV35jfoRwD2yYF3QSp1hEookMU5sd6Q6Pt6RpSrl4Cf9KEfme8rg==","_npmVersion":"10.8.2","description":"Normalizes TypeScript declaration files","directories":{},"_nodeVersion":"20.19.6","dependencies":{"typescript":"5.8.3"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.15","@types/node":"^22.10.2","@vitest/coverage-v8":"^4.0.15","@microsoft/api-extractor":"^7.55.1"},"_npmOperationalInternal":{"tmp":"tmp/declaration-file-normalizer_0.1.0-alpha.4_1767573583653_0.9451473868387721","host":"s3://npm-registry-packages-npm-production"}},"0.1.0-alpha.5":{"name":"@api-extractor-tools/declaration-file-normalizer","version":"0.1.0-alpha.5","keywords":[],"author":"","license":"MIT","_id":"@api-extractor-tools/declaration-file-normalizer@0.1.0-alpha.5","maintainers":[{"name":"northm","email":"michael.l.north@gmail.com"}],"bin":{"declaration-file-normalizer":"dist/cli.js"},"dist":{"shasum":"f41009b2d0b06cfc1772cb86c1973b947b20417d","tarball":"https://registry.npmjs.org/@api-extractor-tools/declaration-file-normalizer/-/declaration-file-normalizer-0.1.0-alpha.5.tgz","fileCount":47,"integrity":"sha512-d1ohGOoC5dMWvWGimCBLRhYtgAgDQfijYVu23YqnFonXS5Fut4phz2OKo9DSjdMpagMKMD+089Ramqf2pzYQYw==","signatures":[{"sig":"MEUCIFFmQ0Ua+G9RfQiCpmoFOeefDWYODQnP7/KKp0D/n17vAiEAuVSqVh6QNlSdP+N2C5V61q/fjZicWQWTliSC6xfd8Cc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":203400},"main":"dist/index.js","type":"module","_from":"file:api-extractor-tools-declaration-file-normalizer-0.1.0-alpha.5.tgz","types":"dist/declaration-file-normalizer-public.d.ts","scripts":{"test":"vitest run","build":"tsc && node dist/cli.js dist/index.d.ts && api-extractor run --local","check":"pnpm check:eslint && pnpm check:typecheck-tests && pnpm check:api-report","clean":"rm -rf dist","check:eslint":"eslint src test","test:coverage":"vitest run --coverage","check:api-report":"api-extractor run","generate:api-report":"api-extractor run --local --verbose","check:typecheck-tests":"tsc -p test/tsconfig.json"},"_npmUser":{"name":"northm","email":"michael.l.north@gmail.com"},"_resolved":"/tmp/d6d6256d4f82813d16505e776cc9c2ed/api-extractor-tools-declaration-file-normalizer-0.1.0-alpha.5.tgz","_integrity":"sha512-d1ohGOoC5dMWvWGimCBLRhYtgAgDQfijYVu23YqnFonXS5Fut4phz2OKo9DSjdMpagMKMD+089Ramqf2pzYQYw==","_npmVersion":"10.8.2","description":"Normalizes TypeScript declaration files","directories":{},"_nodeVersion":"20.19.6","dependencies":{"typescript":"5.8.3"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.15","@types/node":"^22.10.2","@vitest/coverage-v8":"^4.0.15","@microsoft/api-extractor":"^7.55.1"},"_npmOperationalInternal":{"tmp":"tmp/declaration-file-normalizer_0.1.0-alpha.5_1767595987346_0.3858319478123531","host":"s3://npm-registry-packages-npm-production"}},"0.1.0-alpha.6":{"name":"@api-extractor-tools/declaration-file-normalizer","version":"0.1.0-alpha.6","keywords":[],"author":"","license":"MIT","_id":"@api-extractor-tools/declaration-file-normalizer@0.1.0-alpha.6","maintainers":[{"name":"northm","email":"michael.l.north@gmail.com"}],"bin":{"declaration-file-normalizer":"dist/cli.js"},"dist":{"shasum":"7781177589a09dbcb3f599083879a5d72dbef088","tarball":"https://registry.npmjs.org/@api-extractor-tools/declaration-file-normalizer/-/declaration-file-normalizer-0.1.0-alpha.6.tgz","fileCount":47,"integrity":"sha512-7qK2KDoEBEnkY81W3ZlgIWQw5YWzabSshFy2GuyvIsjB5JdNy3tjZP2yNy+HQ4M+DOFJbMbDIy2IxabZZXIqTw==","signatures":[{"sig":"MEQCIFP+VgIajCkKPnGtbbutRc78LeeFWQ9lW7n/kqEtPxGkAiBQl9bagrAbs48bOpsDuV1cqPobB0hWRfFsjULzxR7kHA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":205004},"main":"dist/index.js","type":"module","_from":"file:api-extractor-tools-declaration-file-normalizer-0.1.0-alpha.6.tgz","types":"dist/declaration-file-normalizer-public.d.ts","scripts":{"test":"vitest run","build":"tsc && node dist/cli.js dist/index.d.ts && api-extractor run --local","check":"pnpm check:eslint && pnpm check:typecheck-tests && pnpm check:api-report","clean":"rm -rf dist","check:eslint":"eslint src test","test:coverage":"vitest run --coverage","check:api-report":"api-extractor run","generate:api-report":"api-extractor run --local --verbose","check:typecheck-tests":"tsc -p test/tsconfig.json"},"_npmUser":{"name":"northm","email":"michael.l.north@gmail.com"},"_resolved":"/tmp/504dce8e5b7fdfb75281079cdd44cf98/api-extractor-tools-declaration-file-normalizer-0.1.0-alpha.6.tgz","_integrity":"sha512-7qK2KDoEBEnkY81W3ZlgIWQw5YWzabSshFy2GuyvIsjB5JdNy3tjZP2yNy+HQ4M+DOFJbMbDIy2IxabZZXIqTw==","_npmVersion":"10.8.2","description":"Normalizes TypeScript declaration files","directories":{},"_nodeVersion":"20.19.6","dependencies":{"typescript":"5.8.3"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.0.15","@types/node":"^22.10.2","@vitest/coverage-v8":"^4.0.15","@microsoft/api-extractor":"^7.55.1"},"_npmOperationalInternal":{"tmp":"tmp/declaration-file-normalizer_0.1.0-alpha.6_1768370472610_0.0034350432393226438","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@api-extractor-tools/declaration-file-normalizer","version":"0.1.0","description":"Normalizes TypeScript declaration files","type":"module","main":"dist/index.js","types":"dist/declaration-file-normalizer-public.d.ts","bin":{"declaration-file-normalizer":"dist/cli.js"},"keywords":[],"author":"","license":"MIT","dependencies":{"typescript":"5.8.3"},"devDependencies":{"@microsoft/api-extractor":"^7.55.1","@types/node":"^22.10.2","@vitest/coverage-v8":"^4.0.15","vitest":"^4.0.15"},"scripts":{"clean":"rm -rf dist","build":"tsc && node dist/cli.js dist/index.d.ts && api-extractor run --local","generate:api-report":"api-extractor run --local --verbose","test":"vitest run","test:coverage":"vitest run --coverage","check":"pnpm check:eslint && pnpm check:typecheck-tests && pnpm check:api-report","check:eslint":"eslint src test","check:typecheck-tests":"tsc -p test/tsconfig.json","check:api-report":"api-extractor run"},"_id":"@api-extractor-tools/declaration-file-normalizer@0.1.0","_integrity":"sha512-ehBWK2uC8e4z+yoNdYKbmSDjSoZjmrbRPaQZM7plLqYkmD1HIMDgp3FrLgkIPEEKVZc1KimXwtkO4rKs7hR5lg==","_resolved":"/tmp/3b8eda46c8f854afb3362992e083b89b/api-extractor-tools-declaration-file-normalizer-0.1.0.tgz","_from":"file:api-extractor-tools-declaration-file-normalizer-0.1.0.tgz","_nodeVersion":"20.20.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-ehBWK2uC8e4z+yoNdYKbmSDjSoZjmrbRPaQZM7plLqYkmD1HIMDgp3FrLgkIPEEKVZc1KimXwtkO4rKs7hR5lg==","shasum":"1c936d508c30db71817e5c858b480b3f25628bcb","tarball":"https://registry.npmjs.org/@api-extractor-tools/declaration-file-normalizer/-/declaration-file-normalizer-0.1.0.tgz","fileCount":47,"unpackedSize":210658,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDc+xCcqSPdKI23EzefZOWy68MMfu8s7XW/W6p50IlJ9QIgEWgXMkXpwhUgckUCd0ItK2j9ilnV01B1QMPvI0AiHlU="}]},"_npmUser":{"name":"northm","email":"michael.l.north@gmail.com"},"directories":{},"maintainers":[{"name":"northm","email":"michael.l.north@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/declaration-file-normalizer_0.1.0_1771015666397_0.2500305718128031"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-01T21:47:21.303Z","modified":"2026-02-13T20:47:46.712Z","0.0.1-alpha.2":"2026-01-01T21:47:21.543Z","0.1.0-alpha.3":"2026-01-04T22:12:15.451Z","0.1.0-alpha.4":"2026-01-05T00:39:43.800Z","0.1.0-alpha.5":"2026-01-05T06:53:07.484Z","0.1.0-alpha.6":"2026-01-14T06:01:12.775Z","0.1.0":"2026-02-13T20:47:46.562Z"},"license":"MIT","keywords":[],"description":"Normalizes TypeScript declaration files","maintainers":[{"name":"northm","email":"michael.l.north@gmail.com"}],"readme":"# @api-extractor-tools/declaration-file-normalizer\n\nA TypeScript tool that normalizes union and intersection type ordering in declaration files to ensure stable API reports from Microsoft's API Extractor.\n\n## Problem Statement\n\nTypeScript's compiler can produce declaration files with inconsistent ordering of union and intersection type members across builds, even when the source code hasn't changed. This causes:\n\n- Semi-random shuffling of type members in API reports\n- Unnecessary churn in API report files\n- False positives in CI checks that validate API reports\n\n## Solution\n\nThis tool parses TypeScript declaration files, identifies all composite types (unions, intersections, and object type literals), and rewrites them with stable alphanumeric (case-sensitive) ordering using `localeCompare`.\n\n> **Note**: The main function is named `normalizeUnionTypes()` for historical reasons, but it normalizes union types, intersection types, AND object type properties. This naming may be updated in a future major version.\n\n## Installation\n\nThis tool is part of the monorepo and installed automatically when you run `pnpm install` at the workspace root.\n\n## Usage\n\n### CLI\n\n```bash\n# Basic usage (from workspace root)\npnpm --filter @api-extractor-tools/declaration-file-normalizer exec declaration-file-normalizer <path-to-entry-point.d.ts>\n\n# Or using the binary directly\n./tools/declaration-file-normalizer/dist/cli.js <path-to-entry-point.d.ts>\n\n# Dry run (preview changes without writing)\npnpm --filter @api-extractor-tools/declaration-file-normalizer exec declaration-file-normalizer --dry-run <path-to-entry-point.d.ts>\n\n# Verbose output\npnpm --filter @api-extractor-tools/declaration-file-normalizer exec declaration-file-normalizer --verbose <path-to-entry-point.d.ts>\n\n# Show help\npnpm --filter @api-extractor-tools/declaration-file-normalizer exec declaration-file-normalizer --help\n```\n\n### Examples\n\n```bash\n# Normalize a package's declaration files\npnpm --filter @api-extractor-tools/declaration-file-normalizer exec declaration-file-normalizer tools/change-detector/dist/index.d.ts\n\n# Preview what would change\npnpm --filter @api-extractor-tools/declaration-file-normalizer exec declaration-file-normalizer --dry-run --verbose tools/change-detector/dist/index.d.ts\n```\n\n### Programmatic API\n\n```typescript\nimport { normalizeUnionTypes } from '@api-extractor-tools/declaration-file-normalizer'\n\nconst result = normalizeUnionTypes({\n  entryPoint: 'tools/change-detector/dist/index.d.ts',\n  dryRun: false,\n  verbose: true,\n})\n\nif (result.errors.length > 0) {\n  console.error('Normalization encountered errors:')\n  result.errors.forEach(({ file, error }) => {\n    console.error(`  ${file}: ${error}`)\n  })\n  process.exit(1)\n}\n\nconsole.log(\n  `✓ Successfully normalized ${result.typesNormalized} types in ${result.filesProcessed} files`,\n)\nif (result.modifiedFiles.length > 0) {\n  console.log('  Modified files:')\n  result.modifiedFiles.forEach((file) => console.log(`    - ${file}`))\n}\n```\n\n## API Reference\n\n### `normalizeUnionTypes(options: NormalizerOptions): NormalizationResult`\n\nNormalizes union and intersection type ordering in TypeScript declaration files.\n\n**Note**: Despite the function name `normalizeUnionTypes`, this function normalizes BOTH union types (`A | B`) and intersection types (`A & B`). The name is historical and may be updated in a future major version.\n\n#### Parameters\n\n- **`options.entryPoint`** (string, required): Path to the entry point `.d.ts` file (relative or absolute)\n- **`options.dryRun`** (boolean, optional): If true, analyzes files but doesn't write changes. Default: `false`\n- **`options.verbose`** (boolean, optional): If true, outputs detailed progress information. Default: `false`\n\n#### Returns: `NormalizationResult`\n\n- **`filesProcessed`**: Total number of declaration files analyzed\n- **`typesNormalized`**: Count of composite types that required reordering (0 if all were already sorted)\n- **`modifiedFiles`**: Array of absolute file paths that were changed (empty in dry-run mode)\n- **`errors`**: Array of error objects with `file` path and `error` message. Empty if successful.\n\n#### Behavior\n\n- Processes the entry point file and recursively follows all relative imports\n- Skips `node_modules` and non-relative imports (e.g., `'typescript'`, `'node:fs'`)\n- Modifies files in-place using atomic writes (unless `dryRun: true`)\n- Does not throw exceptions - all errors are returned in the result object\n- Uses stable alphanumeric sorting with `localeCompare` (case-sensitive)\n\n#### Example: Error Handling\n\n```typescript\nimport { normalizeUnionTypes } from '@api-extractor-tools/declaration-file-normalizer'\n\nconst result = normalizeUnionTypes({\n  entryPoint: './dist/index.d.ts',\n  dryRun: false,\n  verbose: true,\n})\n\n// Check for errors\nif (result.errors.length > 0) {\n  console.error('Normalization failed:')\n  for (const { file, error } of result.errors) {\n    console.error(`  ${file}: ${error}`)\n  }\n  process.exit(1)\n}\n\n// Report success\nconsole.log(\n  `Normalized ${result.typesNormalized} types in ${result.filesProcessed} files`,\n)\n```\n\n#### Example: Dry-Run Mode\n\n```typescript\n// Preview what would change without modifying files\nconst result = normalizeUnionTypes({\n  entryPoint: './dist/index.d.ts',\n  dryRun: true,\n  verbose: true,\n})\n\nconsole.log(\n  `Would normalize ${result.typesNormalized} types in ${result.filesProcessed} files`,\n)\nconsole.log(`Would modify ${result.modifiedFiles.length} files`)\n```\n\n## How It Works\n\n1. **Entry Point**: Starts with the specified `.d.ts` file\n2. **Graph Building**: Follows all `import` declarations to build a complete file graph\n3. **AST Parsing**: Uses the TypeScript Compiler API to parse each file\n4. **Recursive Normalization**: Recursively traverses type nodes from inside-out:\n   - Processes nested types before their parents\n   - Handles union types, intersection types, object types, function signatures, mapped types, conditional types, indexed access types, tuples, and more\n   - Sorts members alphanumerically at each level\n5. **Writing**: Applies transformations in-place (from end to beginning to avoid offset issues)\n\n## Sorting Behavior\n\n- **Algorithm**: Uses `localeCompare` with `sensitivity: 'variant'` for case-sensitive sorting\n- **Union Example**: `'zebra' | 'apple' | 'Banana'` becomes `'apple' | 'Banana' | 'zebra'`\n- **Intersection Example**: `Zebra & Apple & Banana` becomes `Apple & Banana & Zebra`\n- **Object Type Example**: `{ zebra: string; apple: number }` becomes `{ apple: number; zebra: string }`\n- **Nested Example**: `{ foo: \"z\" | \"a\" }` becomes `{ foo: \"a\" | \"z\" }` (inside-out normalization)\n- **Stability**: Always produces the same output for the same input\n\n## Integration with Build Pipeline\n\n**Important**: This tool should run **immediately after TypeScript compilation**, as part of your build step. This ensures normalized declaration files are included in your build output cache.\n\n### Why Run After `tsc` (Not Before API Extractor)?\n\nIn monorepos with build output caching (e.g., Nx, Turborepo):\n\n1. The build step runs and its output gets cached\n2. Downstream tools (like API Extractor) consume the cached build output\n3. If normalization runs _after_ the build step but _before_ API Extractor, it modifies files outside the cached build, which can cause cache invalidation or inconsistent results\n\nBy including normalization in the build step itself, the normalized declaration files become part of what gets cached. Any downstream tool can then consume the build output—whether cached or freshly calculated—and get consistent results.\n\n### Recommended Integration\n\nUpdate your package's `build` script to include normalization:\n\n```json\n{\n  \"scripts\": {\n    \"build\": \"tsc && declaration-file-normalizer dist/index.d.ts\",\n    \"api-report\": \"api-extractor run --local\",\n    \"api-report:check\": \"api-extractor run\"\n  }\n}\n```\n\nOr if you prefer separate steps:\n\n```json\n{\n  \"scripts\": {\n    \"build:tsc\": \"tsc\",\n    \"build:normalize\": \"declaration-file-normalizer dist/index.d.ts\",\n    \"build\": \"pnpm build:tsc && pnpm build:normalize\",\n    \"api-report\": \"api-extractor run --local\",\n    \"api-report:check\": \"api-extractor run\"\n  }\n}\n```\n\n### Workflow\n\n```text\nbuild step: tsc → declaration-file-normalizer\n    ↓ (output is cached)\napi-extractor (consumes cached or fresh build output)\n```\n\n1. TypeScript emits declaration files (possibly with inconsistent union/intersection ordering)\n2. **`declaration-file-normalizer` runs immediately after `tsc`** to stabilize type ordering in-place\n3. The build output (including normalized `.d.ts` files) is cached\n4. API Extractor processes the normalized files, producing stable API reports\n\n**Key principle**: Normalization is part of the build step, not a pre-step for API Extractor. This ensures build caching works correctly in monorepos.\n\n## Testing\n\n```bash\n# Run tests\npnpm --filter @api-extractor-tools/declaration-file-normalizer test\n\n# Build the tool\npnpm --filter @api-extractor-tools/declaration-file-normalizer build\n\n# Clean build artifacts\npnpm --filter @api-extractor-tools/declaration-file-normalizer clean\n```\n\n## Development\n\n### Project Structure\n\n```text\ntools/declaration-file-normalizer/\n├── src/\n│   ├── cli.ts           # Command-line interface\n│   ├── index.ts         # Main orchestration\n│   ├── parser.ts        # AST parsing & import resolution\n│   ├── normalizer.ts    # Union/intersection type sorting logic\n│   ├── writer.ts        # File transformation\n│   └── types.ts         # TypeScript type definitions\n├── test/\n│   └── index.test.ts\n├── package.json\n├── tsconfig.json\n└── README.md\n```\n\n### Key Files\n\n- **[parser.ts](src/parser.ts)**: Builds the complete file dependency graph by following imports\n- **[normalizer.ts](src/normalizer.ts)**: Recursive type normalization using inside-out AST traversal\n- **[writer.ts](src/writer.ts)**: Applies transformations without breaking offsets\n\n## Troubleshooting\n\n### Tool doesn't find my union/intersection types\n\n- Ensure you're pointing to a `.d.ts` file, not a `.ts` source file\n- Run with `--verbose` to see what files are being processed\n\n### Build fails after normalization\n\n- This tool only modifies type member ordering, not structure\n- Check that your source types are valid TypeScript\n\n### Changes not showing up\n\n- Make sure you're not in `--dry-run` mode\n- Verify the file path is correct (use absolute or relative from cwd)\n\n## License\n\nMIT\n","readmeFilename":"README.md"}