Skip to content

Treat .mts/.cts (TypeScript module extensions) as TypeScript#1607

Closed
ashmitg wants to merge 1 commit into
Graphify-Labs:v8from
ashmitg:add-mts-cts-extensions
Closed

Treat .mts/.cts (TypeScript module extensions) as TypeScript#1607
ashmitg wants to merge 1 commit into
Graphify-Labs:v8from
ashmitg:add-mts-cts-extensions

Conversation

@ashmitg

@ashmitg ashmitg commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Problem

.mts (ESM) and .cts (CommonJS) — the TypeScript counterparts of the already-supported .mjs/.cjs — were handled in neither graphify's code-extension detection nor its TypeScript grammar path. Two compounding effects:

  1. Skipped entirely — absent from CODE_EXTENSIONS, so .mts/.cts files were classified as non-code and never extracted.
  2. Under-parsed even once routed to the JS extractor — the grammar selector picks the TypeScript grammar only for literal .ts/.tsx, so .mts/.cts fell back to the plain JavaScript grammar, which silently drops every type / interface / type-alias.

Real impact: on a TypeScript repo whose tooling/config layer is .mts (files run under tsx/ts-node), those files were dropped from the graph — and where detected, their type surface vanished.

Fix — treat .mts/.cts as TypeScript everywhere .ts is handled

Detection (add alongside .mjs/.cjs/.ts):

File Set
detect.py CODE_EXTENSIONS — the code/non-code gate
analyze.py _LANG_FAMILY"js"
extract.py _JS_RESOLVE_EXTS, _JS_CACHE_BYPASS_SUFFIXES
build.py per-node language map → "js"

TypeScript grammar (.mts/.cts are non-JSX → the plain TypeScript grammar, like .ts):

Site Change
extract_js() grammar selector .mts/.cts_TS_CONFIG
_DISPATCH .mts/.ctsextract_js
use_ts tree-sitter selector include .mts/.cts
typescript_member_calls resolver include .mts/.cts

Same tree-sitter-typescript grammar as .tsno new dependency.

Result (verified on a real 47 KB .mts file)

.mts/.cts now extract identically to .ts — 36 nodes each, vs 22 under the JS grammar. The 14 recovered nodes are exactly the TS type/interface/type-alias declarations the JS grammar was dropping.

Tests

tests/test_typescript_module_extensions.py:

  • membership regression locks for the four extension sets + the _DISPATCH routing, and
  • end-to-end parity: a .mts/.cts source with a type alias + interface captures those TS-only nodes and produces the same node set as the equivalent .ts.

Verified locally (Python 3.12, uv run --frozen): ruff clean · new tests 6/6 · skillgen --check OK (134 artifacts) · broader JS/TS + detection + multilang suites 578 passed, 24 skipped, 0 regressions.

Note

.cjs is in the build.py/analyze.py JS maps but not in detect.CODE_EXTENSIONS (only .mjs is), so .cjs-only files may be detected as non-code too. Kept this PR scoped to .mts/.cts; happy to fold .cjs in if you'd like.

🤖 Generated with Claude Code

`.mts` (ESM) and `.cts` (CommonJS) are the TypeScript counterparts of the
already-supported `.mjs`/`.cjs`, but graphify handled them in neither the
code-extension detection nor the TypeScript grammar path — so they were either
skipped entirely (classified as non-code) or, once detected, parsed with the plain
JavaScript grammar, which silently drops every `type`/`interface`/type-alias
declaration.

Detection — add `.mts`/`.cts` alongside their siblings in:
- detect.CODE_EXTENSIONS            (the code / non-code gate)
- analyze._LANG_FAMILY              (cross-language edge family → "js")
- extract._JS_RESOLVE_EXTS          (import target resolution)
- extract._JS_CACHE_BYPASS_SUFFIXES
- build.py per-node language map    (→ "js")

TypeScript grammar — route `.mts`/`.cts` to the plain TypeScript grammar (like
`.ts`; neither is JSX), so their TS-only syntax is captured:
- extract_js()                      (grammar selector: .mts/.cts → _TS_CONFIG)
- extract._DISPATCH                 (.mts/.cts → extract_js)
- the use_ts tree-sitter selector
- the typescript_member_calls resolver frozenset

Result: a `.mts`/`.cts` file now extracts identically to the equivalent `.ts`.
Verified on a real 47 KB `.mts` source — 36 nodes for `.mts`/`.cts`, matching `.ts`
exactly (was 22 with the JS grammar; the 14 dropped nodes were TS type/interface
declarations). No new dependency — same tree-sitter-typescript grammar as `.ts`.

Tests: tests/test_typescript_module_extensions.py — membership regression locks for
the extension sets, dispatch routing, and end-to-end parity asserting `.mts`/`.cts`
capture the TS `type`/`interface` nodes and match the `.ts` node set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ashmitg ashmitg force-pushed the add-mts-cts-extensions branch from 8702b07 to 0c64a3a Compare July 2, 2026 10:15
@ashmitg ashmitg changed the title Detect .mts/.cts (TypeScript module extensions) as code Treat .mts/.cts (TypeScript module extensions) as TypeScript Jul 2, 2026
safishamsi added a commit that referenced this pull request Jul 2, 2026
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@safishamsi

Copy link
Copy Markdown
Collaborator

Merged into v8 as 1226c34 (your authorship). Thorough — hits all six extension sets (detection, language family, cache-bypass, resolve-exts, resolver registry, dispatch) with locks on each. Verified .mts/.cts route to the TS grammar and .ts is unaffected. Full suite 2841. Ships next release.

@safishamsi safishamsi closed this Jul 2, 2026
safishamsi added a commit that referenced this pull request Jul 4, 2026
The "What files it handles" code row omitted several extensions that reuse
existing tree-sitter grammars (so the grammar count is unchanged): `.mts`/`.cts`
(TypeScript, #1607, new in 0.9.6), `.cc`/`.cxx` (C++), `.kts` (Kotlin), `.psd1`
(PowerShell), `.toc` (Lua). Apex (`.cls`/`.trigger`) and Terraform already have
their own rows. `.r`/`.ejs`/`.ets` are intentionally left out — they are in
CODE_EXTENSIONS but have no registered extractor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants