@siyavuyachagi/typesharp 0.1.3 → 0.1.5-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,279 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseClassesFromFile = parseClassesFromFile;
4
+ const parse_properties_1 = require("./parse-properties");
5
+ const parse_properties_2 = require("./parse-properties");
6
+ /**
7
+ * Parse classes and records from a C# file content
8
+ */
9
+ function parseClassesFromFile(content, targetAnnotation) {
10
+ const classes = [];
11
+ const cleanContent = removeComments(content);
12
+ const annotationRegex = new RegExp(`\\[${targetAnnotation}(?:Attribute)?(?:\\(\\s*"([^"]*)"\\s*\\))?\\]`, 'g');
13
+ const matches = [...cleanContent.matchAll(annotationRegex)];
14
+ for (const match of matches) {
15
+ const startIndex = match.index;
16
+ const afterAnnotation = cleanContent.substring(startIndex);
17
+ // Check if it's an enum
18
+ const enumMatch = afterAnnotation.match(/(?:\[[\w]+(?:\([^)]*\))?\]\s*)*public\s+enum\s+(\w+)/);
19
+ if (enumMatch) {
20
+ const typeNameOverride = match[1] ?? undefined;
21
+ const enumClass = parseEnum(afterAnnotation, typeNameOverride ?? enumMatch[1]);
22
+ if (enumClass)
23
+ classes.push(enumClass);
24
+ continue;
25
+ }
26
+ // Check if it's a record (positional or with body)
27
+ // NOTE: we do NOT capture ctor params in the regex — attributes inside params
28
+ // contain `()` which would break a [^)]* capture group.
29
+ // Use paren-balanced extraction instead.
30
+ const recordMatch = afterAnnotation.match(/(?:\[[\w]+(?:\([^)]*\))?\]\s*)*public\s+(?:sealed\s+|abstract\s+)?record\s+(?:class\s+|struct\s+)?(\w+)(?:<([^>]+)>)?/);
31
+ if (recordMatch) {
32
+ const className = recordMatch[1];
33
+ const genericParams = recordMatch[2];
34
+ // Extract primary ctor params with paren-depth balancing so that
35
+ // attributes like [property: TypeAs("Date")] don't truncate the capture
36
+ const primaryCtorParams = extractPrimaryCtorParams(afterAnnotation);
37
+ // After the ctor (if any), look for `: BaseType<Generics>`
38
+ const ctorOpenIdx = afterAnnotation.indexOf('(');
39
+ const afterCtor = (primaryCtorParams !== undefined && ctorOpenIdx !== -1)
40
+ ? afterAnnotation.slice(ctorOpenIdx + primaryCtorParams.length + 2)
41
+ : afterAnnotation.slice(recordMatch[0].length);
42
+ const inheritMatch = afterCtor.match(/^\s*:\s*(\w+)(?:<([^>]+)>)?/);
43
+ const inheritsFrom = inheritMatch?.[1];
44
+ const baseGenerics = inheritMatch?.[2];
45
+ const resolvedInheritsFrom = inheritsFrom && /^I[A-Z]/.test(inheritsFrom)
46
+ ? undefined
47
+ : inheritsFrom;
48
+ const genericParameters = genericParams
49
+ ? genericParams.split(',').map(p => p.trim())
50
+ : undefined;
51
+ const baseClassGenerics = baseGenerics
52
+ ? baseGenerics.split(',').map(p => p.trim())
53
+ : undefined;
54
+ const typeNameOverride = match[1] ?? undefined;
55
+ // Parse positional primary constructor parameters
56
+ const positionalProperties = primaryCtorParams
57
+ ? (0, parse_properties_2.parseRecordParameters)(primaryCtorParams)
58
+ : [];
59
+ // Also parse any body properties (records can have both)
60
+ const classBody = extractClassBody(afterAnnotation);
61
+ const bodyProperties = classBody
62
+ ? (0, parse_properties_1.parseProperties)(classBody)
63
+ : [];
64
+ // Deduplicate: body props take priority if name clashes
65
+ const bodyPropNames = new Set(bodyProperties.map(p => p.name));
66
+ const mergedProperties = [
67
+ ...positionalProperties.filter(p => !bodyPropNames.has(p.name)),
68
+ ...bodyProperties,
69
+ ];
70
+ classes.push({
71
+ name: typeNameOverride ?? className,
72
+ properties: mergedProperties,
73
+ inheritsFrom: resolvedInheritsFrom,
74
+ isEnum: false,
75
+ isRecord: true,
76
+ genericParameters,
77
+ baseClassGenerics: resolvedInheritsFrom ? baseClassGenerics : undefined,
78
+ });
79
+ continue;
80
+ }
81
+ // Regular class
82
+ const classMatch = afterAnnotation.match(/(?:\[[\w]+(?:\([^)]*\))?\]\s*)*public\s+class\s+(\w+)(?:<([^>]+)>)?(?:\s*:\s*(\w+)(?:<([^>]+)>)?)?/);
83
+ if (classMatch) {
84
+ const className = classMatch[1];
85
+ const genericParams = classMatch[2];
86
+ const inheritsFrom = classMatch[3];
87
+ const baseGenerics = classMatch[4];
88
+ const resolvedInheritsFrom = inheritsFrom && /^I[A-Z]/.test(inheritsFrom)
89
+ ? undefined
90
+ : inheritsFrom;
91
+ const classBody = extractClassBody(afterAnnotation);
92
+ if (classBody) {
93
+ const { cleanedBody, injectedProperties } = stripNestedAnnotatedClasses(classBody, targetAnnotation);
94
+ const properties = [
95
+ ...(0, parse_properties_1.parseProperties)(cleanedBody),
96
+ ...injectedProperties
97
+ ];
98
+ const genericParameters = genericParams
99
+ ? genericParams.split(',').map(p => p.trim())
100
+ : undefined;
101
+ const baseClassGenerics = baseGenerics
102
+ ? baseGenerics.split(',').map(p => p.trim())
103
+ : undefined;
104
+ const typeNameOverride = match[1] ?? undefined;
105
+ classes.push({
106
+ name: typeNameOverride ?? className,
107
+ properties,
108
+ inheritsFrom: resolvedInheritsFrom,
109
+ isEnum: false,
110
+ isRecord: false,
111
+ genericParameters,
112
+ baseClassGenerics: resolvedInheritsFrom ? baseClassGenerics : undefined
113
+ });
114
+ }
115
+ }
116
+ }
117
+ return classes;
118
+ }
119
+ /**
120
+ * Parse enum from C# content
121
+ */
122
+ function parseEnum(content, enumName) {
123
+ const enumBodyMatch = content.match(/enum\s+\w+\s*\{([^}]+)\}/);
124
+ if (!enumBodyMatch)
125
+ return null;
126
+ const enumBody = enumBodyMatch[1];
127
+ const enumValues = enumBody
128
+ .split(',')
129
+ .map(v => v.trim())
130
+ .filter(v => v.length > 0)
131
+ .map(v => v.split('=')[0].trim());
132
+ return {
133
+ name: enumName,
134
+ properties: [],
135
+ isEnum: true,
136
+ isRecord: false,
137
+ enumValues
138
+ };
139
+ }
140
+ /**
141
+ * Extract class body between curly braces
142
+ */
143
+ function extractClassBody(content) {
144
+ let braceCount = 0;
145
+ let startIndex = -1;
146
+ for (let i = 0; i < content.length; i++) {
147
+ if (content[i] === '{') {
148
+ if (braceCount === 0)
149
+ startIndex = i;
150
+ braceCount++;
151
+ }
152
+ else if (content[i] === '}') {
153
+ braceCount--;
154
+ if (braceCount === 0 && startIndex !== -1) {
155
+ return content.substring(startIndex + 1, i);
156
+ }
157
+ }
158
+ }
159
+ return null;
160
+ }
161
+ /**
162
+ * Extract the primary constructor parameter string from a record declaration,
163
+ * using paren-depth balancing so attribute parens like `[property: TypeAs("Date")]`
164
+ * don't cause early termination.
165
+ *
166
+ * Returns the raw content between the outermost `(` and its matching `)`,
167
+ * or undefined if no primary constructor is present (body-only record).
168
+ *
169
+ * The search starts after the class/record name so that attribute parens on
170
+ * the annotation itself are skipped.
171
+ */
172
+ function extractPrimaryCtorParams(content) {
173
+ // Find the record name first so we skip annotation parens
174
+ const nameIdx = content.search(/\brecord\b/);
175
+ if (nameIdx === -1)
176
+ return undefined;
177
+ // Scan forward from the record keyword for the first `(` that isn't preceded
178
+ // by a `[` sequence (i.e. belongs to the ctor, not an attribute)
179
+ let i = nameIdx;
180
+ // Skip past the record keyword and name (and optional generics)
181
+ // by looking for the first `(` or `{` at the top paren-depth
182
+ let bracketDepth = 0; // tracks [] depth to ignore attr parens
183
+ while (i < content.length) {
184
+ const ch = content[i];
185
+ if (ch === '[') {
186
+ bracketDepth++;
187
+ i++;
188
+ continue;
189
+ }
190
+ if (ch === ']') {
191
+ bracketDepth--;
192
+ i++;
193
+ continue;
194
+ }
195
+ // Only treat `(` as ctor open when we're not inside a `[...]`
196
+ if (ch === '(' && bracketDepth === 0) {
197
+ // Found the ctor opening paren — walk to the matching `)`
198
+ let depth = 0;
199
+ let start = i;
200
+ for (let j = i; j < content.length; j++) {
201
+ if (content[j] === '(')
202
+ depth++;
203
+ else if (content[j] === ')') {
204
+ depth--;
205
+ if (depth === 0) {
206
+ return content.slice(start + 1, j);
207
+ }
208
+ }
209
+ }
210
+ return undefined; // unmatched paren
211
+ }
212
+ // A `{` at bracket-depth 0 means we hit the body before a ctor — body-only record
213
+ if (ch === '{' && bracketDepth === 0)
214
+ return undefined;
215
+ i++;
216
+ }
217
+ return undefined;
218
+ }
219
+ /**
220
+ * Remove single-line and multi-line comments
221
+ */
222
+ function removeComments(content) {
223
+ let result = content.replace(/\/\*[\s\S]*?\*\//g, '');
224
+ result = result.replace(/\/\/.*/g, '');
225
+ return result;
226
+ }
227
+ /**
228
+ * Strip nested annotated classes from a class body and inject reference properties.
229
+ */
230
+ function stripNestedAnnotatedClasses(classBody, targetAnnotation) {
231
+ const injectedProperties = [];
232
+ const regionsToRemove = [];
233
+ const annotationRegex = new RegExp(`\\[${targetAnnotation}(?:Attribute)?(?:\\(\\s*"([^"]*)"\\s*\\))?\\]\\s*public\\s+class\\s+(\\w+)`, 'g');
234
+ const matches = [...classBody.matchAll(annotationRegex)];
235
+ for (const match of matches) {
236
+ const typeNameOverride = match[1] ?? undefined;
237
+ const nestedClassName = match[2];
238
+ const resolvedName = typeNameOverride ?? nestedClassName;
239
+ const fromIndex = match.index;
240
+ const afterMatch = classBody.substring(fromIndex);
241
+ const braceStart = afterMatch.indexOf('{');
242
+ if (braceStart === -1)
243
+ continue;
244
+ let depth = 0;
245
+ let end = -1;
246
+ for (let i = braceStart; i < afterMatch.length; i++) {
247
+ if (afterMatch[i] === '{')
248
+ depth++;
249
+ else if (afterMatch[i] === '}') {
250
+ depth--;
251
+ if (depth === 0) {
252
+ end = i;
253
+ break;
254
+ }
255
+ }
256
+ }
257
+ if (end === -1)
258
+ continue;
259
+ regionsToRemove.push({
260
+ start: fromIndex,
261
+ end: fromIndex + braceStart + end + 1
262
+ });
263
+ const propName = nestedClassName.charAt(0).toLowerCase() + nestedClassName.slice(1);
264
+ injectedProperties.push({
265
+ name: propName,
266
+ type: resolvedName,
267
+ isNullable: false,
268
+ isArray: false,
269
+ isGeneric: false,
270
+ isDeprecated: false,
271
+ });
272
+ }
273
+ let cleanedBody = classBody;
274
+ for (const region of regionsToRemove.reverse()) {
275
+ cleanedBody = cleanedBody.substring(0, region.start) + cleanedBody.substring(region.end);
276
+ }
277
+ return { cleanedBody, injectedProperties };
278
+ }
279
+ //# sourceMappingURL=parse-classes-from-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-classes-from-file.js","sourceRoot":"","sources":["../../src/parser/parse-classes-from-file.ts"],"names":[],"mappings":"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"}
@@ -3,4 +3,26 @@ import { CSharpProperty } from "../types";
3
3
  * Parse properties from class body
4
4
  */
5
5
  export declare function parseProperties(classBody: string): CSharpProperty[];
6
+ /**
7
+ * Parse positional primary constructor parameters from a C# record declaration.
8
+ *
9
+ * Handles:
10
+ * - Simple types: int Id
11
+ * - Nullable types: string? Name
12
+ * - Generic types: List<string> Tags
13
+ * - Nested generics: Dictionary<string, List<int>> Map
14
+ * - Per-parameter attributes with the `property:` target (required by C# for ctor params):
15
+ * [property: TypeIgnore]
16
+ * [property: TypeName("x")]
17
+ * [property: TypeAs("y")]
18
+ * [property: Obsolete("msg")]
19
+ * - [Obsolete] / [Obsolete("msg")]
20
+ *
21
+ * Note: [TypeAs], [TypeName], [TypeIgnore] on record primary constructor parameters
22
+ * MUST use the `property:` attribute target in C#:
23
+ * public record Foo([property: TypeAs("Date")] DateTime CreatedAt);
24
+ *
25
+ * @param raw - The raw text between the record's primary constructor parentheses
26
+ */
27
+ export declare function parseRecordParameters(raw: string): CSharpProperty[];
6
28
  //# sourceMappingURL=parse-properties.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-properties.d.ts","sourceRoot":"","sources":["../../src/parser/parse-properties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,EAAE,CAsDnE"}
1
+ {"version":3,"file":"parse-properties.d.ts","sourceRoot":"","sources":["../../src/parser/parse-properties.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,EAAE,CAsDnE;AAGD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CA8DnE"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseProperties = parseProperties;
4
+ exports.parseRecordParameters = parseRecordParameters;
4
5
  /**
5
6
  * Parse properties from class body
6
7
  */
@@ -48,16 +49,189 @@ function parseProperties(classBody) {
48
49
  }
49
50
  return properties;
50
51
  }
52
+ /**
53
+ * Parse positional primary constructor parameters from a C# record declaration.
54
+ *
55
+ * Handles:
56
+ * - Simple types: int Id
57
+ * - Nullable types: string? Name
58
+ * - Generic types: List<string> Tags
59
+ * - Nested generics: Dictionary<string, List<int>> Map
60
+ * - Per-parameter attributes with the `property:` target (required by C# for ctor params):
61
+ * [property: TypeIgnore]
62
+ * [property: TypeName("x")]
63
+ * [property: TypeAs("y")]
64
+ * [property: Obsolete("msg")]
65
+ * - [Obsolete] / [Obsolete("msg")]
66
+ *
67
+ * Note: [TypeAs], [TypeName], [TypeIgnore] on record primary constructor parameters
68
+ * MUST use the `property:` attribute target in C#:
69
+ * public record Foo([property: TypeAs("Date")] DateTime CreatedAt);
70
+ *
71
+ * @param raw - The raw text between the record's primary constructor parentheses
72
+ */
73
+ function parseRecordParameters(raw) {
74
+ const properties = [];
75
+ // Split on top-level commas (skip commas inside angle brackets or square brackets)
76
+ const params = splitTopLevelParams(raw);
77
+ for (const param of params) {
78
+ const trimmed = param.trim();
79
+ if (!trimmed)
80
+ continue;
81
+ // Extract all [Attr] tokens from the front of the param string,
82
+ // then treat the remainder as "type name".
83
+ // This handles both inline attrs ([TypeAs("x")] DateTime CreatedAt)
84
+ // and multiline attrs (separate lines with \n between them).
85
+ const { attrTokens, remainder } = extractLeadingAttributes(trimmed);
86
+ const typeAndName = remainder.trim();
87
+ if (!typeAndName)
88
+ continue;
89
+ // Check [TypeIgnore] — supports [property: TypeIgnore]
90
+ const ignore = attrTokens.some(l => /\[\s*(?:property\s*:\s*)?TypeIgnore\]/.test(l));
91
+ if (ignore)
92
+ continue;
93
+ // Check [TypeName("x")] — supports [property: TypeName("x")]
94
+ let overrideName;
95
+ for (const l of attrTokens) {
96
+ const m = l.match(/\[\s*(?:property\s*:\s*)?TypeName\s*\(\s*"([^"]+)"\s*\)\]/);
97
+ if (m) {
98
+ overrideName = m[1];
99
+ break;
100
+ }
101
+ }
102
+ // Check [TypeAs("y")] — supports [property: TypeAs("y")]
103
+ let overrideType;
104
+ for (const l of attrTokens) {
105
+ const m = l.match(/\[\s*(?:property\s*:\s*)?TypeAs\s*\(\s*"([^"]+)"\s*\)\]/);
106
+ if (m) {
107
+ overrideType = m[1];
108
+ break;
109
+ }
110
+ }
111
+ // Check [Obsolete] / [Obsolete("message")] — supports [property: Obsolete("msg")]
112
+ let isDeprecated = false;
113
+ let deprecationMessage;
114
+ for (const l of attrTokens) {
115
+ const m = l.match(/\[\s*(?:property\s*:\s*)?Obsolete(?:Attribute)?\s*(?:\(\s*"([^"]*)"\s*(?:,\s*(?:true|false))?\s*\))?\]/i);
116
+ if (m) {
117
+ isDeprecated = true;
118
+ deprecationMessage = m[1] ?? undefined;
119
+ break;
120
+ }
121
+ }
122
+ // Parse "TypeToken NameToken" — handle nested generics via angle-bracket depth
123
+ const parsed = parseTypeAndName(typeAndName);
124
+ if (!parsed)
125
+ continue;
126
+ const { csType, name } = parsed;
127
+ const resolvedType = overrideType ?? csType;
128
+ const resolvedName = overrideName ?? name;
129
+ const prop = parsePropertyType(resolvedName, resolvedType);
130
+ properties.push({ ...prop, isDeprecated, deprecationMessage });
131
+ }
132
+ return properties;
133
+ }
134
+ /**
135
+ * Walk a parameter string and peel off every leading [Attr] / [Attr("...")] token,
136
+ * returning them as an array plus the remaining "type name" tail.
137
+ *
138
+ * Works for both inline attrs → "[TypeAs("Date")] DateTime CreatedAt"
139
+ * and multiline attrs → "[Obsolete]\n string OldId"
140
+ */
141
+ function extractLeadingAttributes(s) {
142
+ const attrTokens = [];
143
+ let i = 0;
144
+ // Skip leading whitespace / newlines
145
+ while (i < s.length && /\s/.test(s[i]))
146
+ i++;
147
+ while (i < s.length && s[i] === '[') {
148
+ // Find the matching ']', respecting nested brackets (e.g. [Obsolete("msg")])
149
+ let depth = 0;
150
+ let end = i;
151
+ for (let j = i; j < s.length; j++) {
152
+ if (s[j] === '[')
153
+ depth++;
154
+ else if (s[j] === ']') {
155
+ depth--;
156
+ if (depth === 0) {
157
+ end = j;
158
+ break;
159
+ }
160
+ }
161
+ }
162
+ attrTokens.push(s.slice(i, end + 1).trim());
163
+ i = end + 1;
164
+ // Skip whitespace/newlines between attributes or before the type token
165
+ while (i < s.length && /\s/.test(s[i]))
166
+ i++;
167
+ }
168
+ return { attrTokens, remainder: s.slice(i) };
169
+ }
170
+ /**
171
+ * Split a raw parameter string on top-level commas
172
+ * (i.e. commas not inside <> or [])
173
+ */
174
+ function splitTopLevelParams(raw) {
175
+ const parts = [];
176
+ let depth = 0;
177
+ let buf = '';
178
+ for (let i = 0; i < raw.length; i++) {
179
+ const ch = raw[i];
180
+ if (ch === '<' || ch === '[') {
181
+ depth++;
182
+ buf += ch;
183
+ }
184
+ else if (ch === '>' || ch === ']') {
185
+ depth--;
186
+ buf += ch;
187
+ }
188
+ else if (ch === ',' && depth === 0) {
189
+ parts.push(buf);
190
+ buf = '';
191
+ }
192
+ else {
193
+ buf += ch;
194
+ }
195
+ }
196
+ if (buf.trim())
197
+ parts.push(buf);
198
+ return parts;
199
+ }
200
+ /**
201
+ * Parse a "TypeToken NameToken" string where TypeToken may contain generics.
202
+ * Returns null if the string doesn't look like a valid type+name pair.
203
+ */
204
+ function parseTypeAndName(s) {
205
+ s = s.trim();
206
+ // Walk the string tracking angle-bracket depth to find the boundary
207
+ // between the type token and the name token
208
+ let depth = 0;
209
+ let splitAt = -1;
210
+ // Find the last space at depth 0 — that separates type from name
211
+ for (let i = 0; i < s.length; i++) {
212
+ if (s[i] === '<')
213
+ depth++;
214
+ else if (s[i] === '>')
215
+ depth--;
216
+ else if (s[i] === ' ' && depth === 0) {
217
+ splitAt = i;
218
+ }
219
+ }
220
+ if (splitAt === -1)
221
+ return null;
222
+ const csType = s.slice(0, splitAt).trim();
223
+ const name = s.slice(splitAt + 1).trim();
224
+ if (!csType || !name)
225
+ return null;
226
+ return { csType, name };
227
+ }
51
228
  function extractObsoleteInfo(classBody, matchIndex) {
52
229
  const before = classBody.substring(0, matchIndex);
53
230
  const lines = before.split('\n');
54
- // Walk backwards, only through attribute lines and whitespace
55
- // Stop as soon as we hit a line that isn't an attribute or blank
56
231
  for (let i = lines.length - 1; i >= 0; i--) {
57
232
  const line = lines[i].trim();
58
233
  if (line === '')
59
234
  continue;
60
- // If it's an attribute line, check for Obsolete
61
235
  if (line.startsWith('[')) {
62
236
  const obsoleteMatch = line.match(/\[Obsolete(?:Attribute)?\s*(?:\(\s*"([^"]*)"\s*(?:,\s*(?:true|false))?\s*\))?\]/i);
63
237
  if (obsoleteMatch) {
@@ -66,10 +240,8 @@ function extractObsoleteInfo(classBody, matchIndex) {
66
240
  deprecationMessage: obsoleteMatch[1] ?? undefined
67
241
  };
68
242
  }
69
- // It's a different attribute — keep walking back (stacked attributes)
70
243
  continue;
71
244
  }
72
- // Hit a non-attribute, non-blank line — stop looking
73
245
  break;
74
246
  }
75
247
  return { isDeprecated: false };
@@ -100,25 +272,18 @@ function extractTypeSharpAttributeInfo(classBody, matchIndex) {
100
272
  function parsePropertyType(name, csType) {
101
273
  let raw = csType.trim();
102
274
  let isNullable = false;
103
- // Extract nullable marker (T?)
104
275
  if (raw.endsWith('?')) {
105
276
  isNullable = true;
106
277
  raw = raw.slice(0, -1).trim();
107
278
  }
108
- // Recursive resolver: returns { tsType, isArray }
109
279
  function resolveType(typeText) {
110
280
  const t = typeText.trim();
111
- // 1) Array syntax: T[]
112
281
  if (t.endsWith('[]')) {
113
282
  const inner = t.slice(0, -2).trim();
114
283
  const resolved = resolveType(inner);
115
- // If inner is already an array, keep it as array-of-array semantics;
116
- // mark as array so generator will append [] (or use resolved.tsType which may include [] already)
117
284
  return { tsType: resolved.tsType, isArray: true };
118
285
  }
119
- // 2) Dictionary-like types (handle Dictionary, IDictionary, IReadOnlyDictionary)
120
286
  if (/^(?:[\w\.]+\.)?(?:Dictionary|IDictionary|IReadOnlyDictionary)\s*</.test(t)) {
121
- // locate first '<' and its matching '>'
122
287
  const firstAngle = t.indexOf('<');
123
288
  const lastAngle = findMatchingAngleBracket(t, firstAngle);
124
289
  if (firstAngle !== -1 && lastAngle !== -1) {
@@ -127,36 +292,26 @@ function parsePropertyType(name, csType) {
127
292
  if (args.length === 2) {
128
293
  const keyCs = args[0];
129
294
  const valueCs = args[1];
130
- // Guard against undefined/null/empty parts before resolving
131
295
  if (typeof keyCs !== 'string' || typeof valueCs !== 'string' || keyCs.trim() === '' || valueCs.trim() === '') {
132
- // Fallback: avoid throwing — emit a generic record
133
296
  return { tsType: 'Record<string, any>', isArray: false };
134
297
  }
135
298
  const resolvedKey = resolveType(keyCs);
136
299
  const resolvedValue = resolveType(valueCs);
137
- // Normalize key to a safe TS key type: Record<K extends keyof any, V>
138
- // If key is not primitive 'string' or 'number' or 'symbol', coerce to 'string'
139
300
  const keyTsRaw = resolvedKey.tsType;
140
301
  const safeKey = keyTsRaw === 'string' || keyTsRaw === 'number' || keyTsRaw === 'symbol'
141
302
  ? keyTsRaw
142
303
  : 'string';
143
- // Build value type (respect nested arrays)
144
304
  const valueType = resolvedValue.isArray ? `${resolvedValue.tsType}[]` : resolvedValue.tsType;
145
305
  return { tsType: `Record<${safeKey}, ${valueType}>`, isArray: false };
146
306
  }
147
- // else: fallthrough to other checks (malformed or >2 args) — do not falsely match
148
307
  }
149
308
  }
150
- // 3) Collections: List<T>, IEnumerable<T>, ICollection<T>, IList<T>
151
309
  const collectionMatch = t.match(/^(?:List|IEnumerable|ICollection|IList)\s*<\s*(.+)\s*>$/);
152
310
  if (collectionMatch) {
153
311
  const inner = collectionMatch[1].trim();
154
312
  const resolvedInner = resolveType(inner);
155
- // Collections become inner[] in TS; mark isArray true and tsType = resolvedInner.tsType
156
- // The generator will append [].
157
313
  return { tsType: resolvedInner.tsType, isArray: true };
158
314
  }
159
- // 4) Fallback: map primitive / known types, else return as-is (class name)
160
315
  return { tsType: mapCSharpTypeToTypeScript(t), isArray: false };
161
316
  }
162
317
  const resolved = resolveType(raw);
@@ -171,10 +326,6 @@ function parsePropertyType(name, csType) {
171
326
  deprecationMessage: undefined,
172
327
  };
173
328
  }
174
- /**
175
- * Find the index of the matching '>' for the first '<' at startIdx.
176
- * Returns -1 if not found.
177
- */
178
329
  function findMatchingAngleBracket(s, startIdx) {
179
330
  let depth = 0;
180
331
  for (let i = startIdx; i < s.length; i++) {
@@ -188,11 +339,6 @@ function findMatchingAngleBracket(s, startIdx) {
188
339
  }
189
340
  return -1;
190
341
  }
191
- /**
192
- * Split a comma-separated generic-argument string into top-level args,
193
- * i.e. respects nested <...> and does NOT split commas inside nested generics.
194
- * Example: "string, List<Dictionary<string, Foo>>, int" -> ["string", "List<Dictionary<string, Foo>>", "int"]
195
- */
196
342
  function splitTopLevelGenericArgs(s) {
197
343
  const parts = [];
198
344
  let depth = 0;
@@ -219,9 +365,6 @@ function splitTopLevelGenericArgs(s) {
219
365
  parts.push(buf.trim());
220
366
  return parts;
221
367
  }
222
- /**
223
- * Map C# primitive types to TypeScript types
224
- */
225
368
  function mapCSharpTypeToTypeScript(csType) {
226
369
  const typeMap = {
227
370
  'bool': 'boolean',