Skip to content

Shorten oversized namespace segments for TypeScript generation#7901

Merged
gavinbarron merged 3 commits into
mainfrom
jingjingjia/ts-shorten-oversized-namespace-segments
Jul 6, 2026
Merged

Shorten oversized namespace segments for TypeScript generation#7901
gavinbarron merged 3 commits into
mainfrom
jingjingjia/ts-shorten-oversized-namespace-segments

Conversation

@jingjingjia-ms

@jingjingjia-ms jingjingjia-ms commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Overview

TypeScript maps namespace segments to directories, but TypeScriptRefiner never called ShortenOversizedNamespaceSegments — unlike the Java, PHP, and Python refiners (which map package/namespace to directory structure and already call it).

As a result, endpoints that produce very long segments generate directory names that exceed the NTFS 255-char per-component limit, failing generation on Windows with Win32 error 123 (ERROR_INVALID_NAME):

error generating the client: The filename, directory name, or volume label syntax is incorrect.

Repro (real case)

The beta function microsoft.graph.networkaccess.deviceReport is bound to networkaccess.reports, returns Collection(networkaccess.device), and takes 8 parameters (2 required + 6 optional: discoveredApplicationSegmentId, applicationId, aiAgentId, aiAgentName, cloudApplicationName, destinationUrl). kiota concatenates these into a single request-builder namespace segment 265 characters long:

networkAccess/reports/microsoftGraphNetworkaccessDeviceReportWithStartDateTimeWithEndDateTimediscoveredApplicationSegmentIdDiscoveredApplicationSegmentIdApplicationIdApplicationIdAiAgentIdAiAgentIdAiAgentNameAiAgentNameCloudApplicationNameCloudApplicationNameDestinationUrlDestinationUrl/

This is a single path component > 255 chars, so LongPathsEnabled / \\?\ / a shorter -o output dir do not help (those address the 260-char total-path limit) — the name itself must be shortened.

Fix

Call ShortenOversizedNamespaceSegments(generatedCode, shortenTypeNames: false) from TypeScriptRefiner (placed right after CorrectCoreTypesForBackingStore, mirroring the Python refiner). Long namespace segments are truncated + suffixed with a deterministic 8-hex hash (threshold 64), consistent with the other directory-structured languages. Type names are left intact (see below). The helper gains a shortenTypeNames flag (default true, preserving Java/PHP/Python behavior) that TypeScript sets to false.

Why not the C#/Go path-segmenter approach?

C# and Go solve the same problem in their path segmenter by hashing the on-disk name (ShortenFileName), leaving the CodeDOM untouched. That works because C#/Go imports resolve by declared namespace/package, not by physical file/folder name — you can scramble a directory to a hash on disk and the code still compiles.

TypeScript can't do this: its imports are relative file paths (import { x } from "./reports/deviceReport.../index.js"), and those paths are computed from the CodeDOM namespace names in TypescriptRelativeImportManagernot from the path segmenter. If we hashed only the on-disk directory (C#/Go style), the folder and the generated import string would derive from two different places and desync:

on disk:   .../reports/3f9a1c...e8b2/index.ts               ← hashed folder
import in:  "./reports/microsoftGraphNetworkaccess.../index.js"  ← still the long name
            => TS2307: Cannot find module

Shortening the namespace in the CodeDOM (the refiner approach) renames it once, so the directory and every relative import derive from the same shortened value and stay consistent. This is why TypeScript follows the Java/Python/PHP refiner model, not the C#/Go segmenter model.

Why shortenTypeNames: false (unlike Java/Python/PHP)?

Java/Python/PHP emit one type per file named after the type, so a 265-char class name also overflows the file name — they must shorten type names too, and it's safe for them.

TypeScript groups many types into a single index.ts barrel per namespace; the file is always named index, never the type. So:

  • The FS limit is only ever hit by the directory (namespace) — shortening namespaces is sufficient.
  • Shortening type names buys zero FS benefit and actively breaks TypeScript's composed-type factory generation, which then emits an invalid return object; instead of the deserializer function. (This surfaced as a Stripe integration-test compile failure on the first iteration of this PR.)

Consumer impact

Same trade-off already accepted for PHP/Python: fluent navigation (client.x.y().get()) is unaffected; only consumers that directly import one of the few long, function-style request builders see a directory rename. Type names are unchanged, so imported symbols keep their names. Bounded and source-breaking only for that niche.

Tests

  • Added ShortensOversizedNamespaceSegmentsAsync in TypeScriptLanguageRefinerTests using the exact deviceReport case, asserting every namespace segment stays <= 64 chars.
  • Regenerated the Stripe TypeScript SDK (the previously failing integration case) and confirmed tsc --noEmit compiles clean — no object errors.
  • Full Kiota.Builder.Tests suite passes.

TypeScript maps namespace segments to directories, but the
TypeScriptRefiner never called ShortenOversizedNamespaceSegments (unlike
the Java, PHP, and Python refiners). Endpoints that produce very long
segments (e.g. the beta microsoft.graph.networkaccess.deviceReport
function with 8 parameters) generated a 265-char directory name that
exceeds the NTFS 255-char per-component limit, failing generation with
Win32 error 123 (ERROR_INVALID_NAME): "The filename, directory name, or
volume label syntax is incorrect".

Call ShortenOversizedNamespaceSegments from TypeScriptRefiner so long
namespace/class/interface/enum names are truncated + hash-suffixed
consistently with the other directory-structured languages.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jingjingjia-ms jingjingjia-ms requested a review from a team as a code owner July 6, 2026 18:04
@msgraph-bot msgraph-bot Bot added this to Kiota Jul 6, 2026
@github-code-quality

github-code-quality Bot commented Jul 6, 2026

Copy link
Copy Markdown

Code Coverage Overview

Languages: C#

C# / code-coverage/dotnet

The overall coverage in the branch is 72%. Coverage data for the branch is not yet available.

Show a code coverage summary of the most covered files.
File f4b8d50 +/-
/home/runner/wo...guageRefiner.cs 98%
/home/runner/wo...criptRefiner.cs 98%
/home/runner/wo...MethodWriter.cs 97%
/home/runner/wo...MethodWriter.cs 96%
/home/runner/wo...MethodWriter.cs 96%
/home/runner/wo...MethodWriter.cs 95%
/home/runner/wo...rs/GoRefiner.cs 93%
/home/runner/wo...KiotaBuilder.cs 90%
/home/runner/wo...ationService.cs 89%
/home/runner/wo...xGenerator.g.cs 75%

Updated July 06, 2026 19:45 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

baywet
baywet previously approved these changes Jul 6, 2026
@github-project-automation github-project-automation Bot moved this to In Progress 🚧 in Kiota Jul 6, 2026
TypeScript maps only namespace segments to directories (types are grouped
into index.ts barrel files), so shortening class/enum/interface names is
unnecessary and breaks name-based composed-type factory generation, which
then emits an invalid 'return object;'. Add a shortenTypeNames flag
(default true, preserving Java/PHP/Python behavior) and pass false from the
TypeScript refiner so only directories are shortened and type names stay intact.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done ✔️

Development

Successfully merging this pull request may close these issues.

3 participants