From b56667c47a3ae1d5c17b23a2d5901b2bdac49da4 Mon Sep 17 00:00:00 2001 From: Mohamed Shams El-Deen Date: Sun, 5 Jul 2026 11:15:34 +0300 Subject: [PATCH 1/2] fix(metadata): support TS prefix operators in typeParser --- .../utils/__tests__/transformers.test.mjs | 18 ++++++++++++++++++ src/generators/metadata/utils/typeParser.mjs | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/src/generators/metadata/utils/__tests__/transformers.test.mjs b/src/generators/metadata/utils/__tests__/transformers.test.mjs index 7405ddcb..fd5a8cd8 100644 --- a/src/generators/metadata/utils/__tests__/transformers.test.mjs +++ b/src/generators/metadata/utils/__tests__/transformers.test.mjs @@ -93,6 +93,24 @@ describe('transformTypeToReferenceLink', () => { ); }); + it('should correctly extract TS prefix operators and link the underlying type', () => { + strictEqual( + transformTypeToReferenceLink('typeof Compiler', { + Compiler: '/api/Compiler', + }), + 'typeof [``](/api/Compiler)' + ); + }); + + it('should not incorrectly strip prefixes if they are part of the type name (word boundary)', () => { + strictEqual( + transformTypeToReferenceLink('typeofSomething', { + typeofSomething: '/api/typeofSomething', + }), + '[``](/api/typeofSomething)' + ); + }); + it('should handle extreme nested combinations of functions, arrays, generics, unions, and intersections', () => { const input = '(str: string[]) => Promise, Map>'; diff --git a/src/generators/metadata/utils/typeParser.mjs b/src/generators/metadata/utils/typeParser.mjs index 5d977379..fa877b7d 100644 --- a/src/generators/metadata/utils/typeParser.mjs +++ b/src/generators/metadata/utils/typeParser.mjs @@ -206,6 +206,14 @@ export const parseType = (typeString, transformType) => { return parts.map(p => resolveOr(p, transformType)).join(joiner); } + const PREFIXES = ['typeof ', 'keyof ', 'readonly ', 'unique ']; + for (const prefix of PREFIXES) { + if (trimmed.startsWith(prefix)) { + const rest = trimmed.slice(prefix.length).trim(); + return `${prefix.trim()} ${resolveOr(rest, transformType)}`; + } + } + // Strip a trailing `[]` for now; reapply on the way out. const isArray = trimmed.endsWith('[]'); const core = isArray ? trimmed.slice(0, -2).trim() : trimmed; From 48fa6351eeca82f2b390c10f5fdaf7974048cb84 Mon Sep 17 00:00:00 2001 From: Mohamed Shams El-Deen Date: Sun, 5 Jul 2026 19:06:38 +0300 Subject: [PATCH 2/2] chore(metadata): put constant PREFIXES in constants.mjs --- src/generators/metadata/constants.mjs | 1 + src/generators/metadata/utils/typeParser.mjs | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generators/metadata/constants.mjs b/src/generators/metadata/constants.mjs index 14d22757..12ed7fd5 100644 --- a/src/generators/metadata/constants.mjs +++ b/src/generators/metadata/constants.mjs @@ -1,6 +1,7 @@ // These openers/closers are used to determine if a type string is well-formed export const TYPE_OPENERS = new Set(['<', '(', '{', '[']); export const TYPE_CLOSERS = new Set(['>', ')', '}', ']']); +export const PREFIXES = ['typeof ', 'keyof ', 'readonly ', 'unique ']; // On "About this Documentation", we define the stability indices, and thus // we don't need to check it for stability references diff --git a/src/generators/metadata/utils/typeParser.mjs b/src/generators/metadata/utils/typeParser.mjs index fa877b7d..e2fcd10b 100644 --- a/src/generators/metadata/utils/typeParser.mjs +++ b/src/generators/metadata/utils/typeParser.mjs @@ -1,4 +1,4 @@ -import { TYPE_OPENERS, TYPE_CLOSERS } from '../constants.mjs'; +import { TYPE_OPENERS, TYPE_CLOSERS, PREFIXES } from '../constants.mjs'; /** True when the `>` at `i` is the tail of `=>` and shouldn't pop depth. */ const isArrowTail = (str, i) => str[i] === '>' && str[i - 1] === '='; @@ -206,7 +206,6 @@ export const parseType = (typeString, transformType) => { return parts.map(p => resolveOr(p, transformType)).join(joiner); } - const PREFIXES = ['typeof ', 'keyof ', 'readonly ', 'unique ']; for (const prefix of PREFIXES) { if (trimmed.startsWith(prefix)) { const rest = trimmed.slice(prefix.length).trim();