@tsonic/cli 0.0.61 → 0.0.62

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.
Files changed (84) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/cli/dispatcher.d.ts.map +1 -1
  3. package/dist/cli/dispatcher.js +13 -5
  4. package/dist/cli/dispatcher.js.map +1 -1
  5. package/dist/cli/help.d.ts.map +1 -1
  6. package/dist/cli/help.js +1 -0
  7. package/dist/cli/help.js.map +1 -1
  8. package/dist/cli/parser.d.ts.map +1 -1
  9. package/dist/cli/parser.js +9 -1
  10. package/dist/cli/parser.js.map +1 -1
  11. package/dist/cli/parser.test.js +9 -1
  12. package/dist/cli/parser.test.js.map +1 -1
  13. package/dist/commands/add-common.d.ts +1 -0
  14. package/dist/commands/add-common.d.ts.map +1 -1
  15. package/dist/commands/add-common.js +37 -3
  16. package/dist/commands/add-common.js.map +1 -1
  17. package/dist/commands/add-common.test.js.map +1 -1
  18. package/dist/commands/add-deps.test.js +1 -8
  19. package/dist/commands/add-deps.test.js.map +1 -1
  20. package/dist/commands/add-framework.d.ts.map +1 -1
  21. package/dist/commands/add-framework.js +3 -1
  22. package/dist/commands/add-framework.js.map +1 -1
  23. package/dist/commands/add-npm.d.ts.map +1 -1
  24. package/dist/commands/add-npm.js +18 -6
  25. package/dist/commands/add-npm.js.map +1 -1
  26. package/dist/commands/add-npm.test.js +24 -9
  27. package/dist/commands/add-npm.test.js.map +1 -1
  28. package/dist/commands/add-nuget.d.ts.map +1 -1
  29. package/dist/commands/add-nuget.js +3 -1
  30. package/dist/commands/add-nuget.js.map +1 -1
  31. package/dist/commands/add-package.d.ts.map +1 -1
  32. package/dist/commands/add-package.js +16 -5
  33. package/dist/commands/add-package.js.map +1 -1
  34. package/dist/commands/build-library-bindings-aliases.test.js +196 -4
  35. package/dist/commands/build-library-bindings-aliases.test.js.map +1 -1
  36. package/dist/commands/build-native-lib.test.js +61 -7
  37. package/dist/commands/build-native-lib.test.js.map +1 -1
  38. package/dist/commands/build-no-generate.test.js +19 -2
  39. package/dist/commands/build-no-generate.test.js.map +1 -1
  40. package/dist/commands/build.d.ts.map +1 -1
  41. package/dist/commands/build.js +37 -9
  42. package/dist/commands/build.js.map +1 -1
  43. package/dist/commands/build.test.d.ts +2 -0
  44. package/dist/commands/build.test.d.ts.map +1 -0
  45. package/dist/commands/build.test.js +106 -0
  46. package/dist/commands/build.test.js.map +1 -0
  47. package/dist/commands/generate.d.ts.map +1 -1
  48. package/dist/commands/generate.js +8 -4
  49. package/dist/commands/generate.js.map +1 -1
  50. package/dist/commands/init.d.ts.map +1 -1
  51. package/dist/commands/init.js +1 -1
  52. package/dist/commands/init.js.map +1 -1
  53. package/dist/commands/init.test.js +1 -1
  54. package/dist/commands/init.test.js.map +1 -1
  55. package/dist/commands/library-bindings-augment.d.ts +10 -0
  56. package/dist/commands/library-bindings-augment.d.ts.map +1 -1
  57. package/dist/commands/library-bindings-augment.js +632 -49
  58. package/dist/commands/library-bindings-augment.js.map +1 -1
  59. package/dist/commands/remove-nuget.d.ts.map +1 -1
  60. package/dist/commands/remove-nuget.js.map +1 -1
  61. package/dist/commands/restore.d.ts.map +1 -1
  62. package/dist/commands/restore.js +59 -15
  63. package/dist/commands/restore.js.map +1 -1
  64. package/dist/commands/restore.test.js +116 -27
  65. package/dist/commands/restore.test.js.map +1 -1
  66. package/dist/commands/run-build-regressions.test.js +42 -8
  67. package/dist/commands/run-build-regressions.test.js.map +1 -1
  68. package/dist/commands/run.d.ts.map +1 -1
  69. package/dist/commands/run.js.map +1 -1
  70. package/dist/commands/test.d.ts.map +1 -1
  71. package/dist/commands/test.js +5 -1
  72. package/dist/commands/test.js.map +1 -1
  73. package/dist/commands/update-nuget.d.ts.map +1 -1
  74. package/dist/commands/update-nuget.js.map +1 -1
  75. package/dist/config.d.ts.map +1 -1
  76. package/dist/config.js +22 -9
  77. package/dist/config.js.map +1 -1
  78. package/dist/dotnet/nuget-config.test.js +1 -1
  79. package/dist/dotnet/nuget-config.test.js.map +1 -1
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +4 -2
  82. package/dist/index.js.map +1 -1
  83. package/package.json +4 -4
  84. package/runtime/nodejs.dll +0 -0
@@ -1,6 +1,6 @@
1
- import { readFileSync, readdirSync, writeFileSync, existsSync } from "node:fs";
2
- import { basename, join, resolve, posix } from "node:path";
3
- import { buildModuleDependencyGraph } from "@tsonic/frontend";
1
+ import { copyFileSync, existsSync, readFileSync, readdirSync, writeFileSync, } from "node:fs";
2
+ import { basename, dirname, join, resolve, posix } from "node:path";
3
+ import { buildModuleDependencyGraph, } from "@tsonic/frontend";
4
4
  import * as ts from "typescript";
5
5
  const renderDiagnostics = (diags) => {
6
6
  return diags
@@ -15,8 +15,30 @@ const renderDiagnostics = (diags) => {
15
15
  const escapeRegExp = (text) => {
16
16
  return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17
17
  };
18
+ const typePrinter = ts.createPrinter({ removeComments: true });
19
+ const printTypeNodeText = (node, sourceFile) => {
20
+ return typePrinter
21
+ .printNode(ts.EmitHint.Unspecified, node, sourceFile)
22
+ .trim();
23
+ };
24
+ const ensureUndefinedInType = (typeText) => {
25
+ const trimmed = typeText.trim();
26
+ if (/\bundefined\b/.test(trimmed))
27
+ return trimmed;
28
+ return `${trimmed} | undefined`;
29
+ };
18
30
  const normalizeModuleFileKey = (filePath) => {
19
- return posix.normalize(filePath).replace(/^(\.\/)+/, "").replace(/^\/+/, "");
31
+ return posix
32
+ .normalize(filePath)
33
+ .replace(/^(\.\/)+/, "")
34
+ .replace(/^\/+/, "");
35
+ };
36
+ const getPropertyNameText = (name) => {
37
+ if (ts.isIdentifier(name))
38
+ return name.text;
39
+ if (ts.isStringLiteral(name) || ts.isNumericLiteral(name))
40
+ return name.text;
41
+ return undefined;
20
42
  };
21
43
  const stripExistingSection = (text, startMarker, endMarker) => {
22
44
  const start = text.indexOf(startMarker);
@@ -35,7 +57,9 @@ const upsertSectionAfterImports = (text, startMarker, endMarker, body) => {
35
57
  while (insertAt < lines.length) {
36
58
  const line = lines[insertAt] ?? "";
37
59
  const trimmed = line.trim();
38
- if (trimmed === "" || trimmed.startsWith("//") || trimmed.startsWith("import ")) {
60
+ if (trimmed === "" ||
61
+ trimmed.startsWith("//") ||
62
+ trimmed.startsWith("import ")) {
39
63
  insertAt += 1;
40
64
  continue;
41
65
  }
@@ -103,7 +127,10 @@ const applyWrappersToBaseType = (baseType, wrappers) => {
103
127
  };
104
128
  const patchInternalIndexWithMemberOverrides = (internalIndexDtsPath, overrides) => {
105
129
  if (!existsSync(internalIndexDtsPath)) {
106
- return { ok: false, error: `Internal index not found at ${internalIndexDtsPath}` };
130
+ return {
131
+ ok: false,
132
+ error: `Internal index not found at ${internalIndexDtsPath}`,
133
+ };
107
134
  }
108
135
  const original = readFileSync(internalIndexDtsPath, "utf-8");
109
136
  // Collect wrapper imports (dedupe + validate no alias conflicts).
@@ -112,7 +139,8 @@ const patchInternalIndexWithMemberOverrides = (internalIndexDtsPath, overrides)
112
139
  for (const w of o.wrappers) {
113
140
  const existing = wrapperByAlias.get(w.aliasName);
114
141
  if (existing) {
115
- if (existing.source !== w.source || existing.importedName !== w.importedName) {
142
+ if (existing.source !== w.source ||
143
+ existing.importedName !== w.importedName) {
116
144
  return {
117
145
  ok: false,
118
146
  error: `Conflicting wrapper import alias '${w.aliasName}' while augmenting ${internalIndexDtsPath}.\n` +
@@ -173,30 +201,239 @@ const patchInternalIndexWithMemberOverrides = (internalIndexDtsPath, overrides)
173
201
  for (const o of list.sort((a, b) => a.memberName.localeCompare(b.memberName))) {
174
202
  const propRe = new RegExp(String.raw `(^\s*(?:readonly\s+)?${escapeRegExp(o.memberName)}\s*:\s*)([^;]+)(;)`, "m");
175
203
  const propMatch = propRe.exec(body);
176
- if (!propMatch) {
204
+ if (propMatch) {
205
+ const baseType = (o.replaceWithSourceType ? o.sourceTypeText : undefined) ??
206
+ propMatch[2] ??
207
+ "";
208
+ let nextType = applyWrappersToBaseType(baseType, o.wrappers);
209
+ if (o.isOptional)
210
+ nextType = ensureUndefinedInType(nextType);
211
+ body = body.replace(propRe, `$1${nextType}$3`);
212
+ continue;
213
+ }
214
+ const getterRe = new RegExp(String.raw `(^\s*get\s+${escapeRegExp(o.memberName)}\s*\(\)\s*:\s*)([^;]+)(;)`, "m");
215
+ const setterRe = new RegExp(String.raw `(^\s*set\s+${escapeRegExp(o.memberName)}\s*\(\s*value\s*:\s*)([^)]+)(\)\s*;)`, "m");
216
+ const getterMatch = getterRe.exec(body);
217
+ const setterMatch = setterRe.exec(body);
218
+ if (!getterMatch && !setterMatch) {
177
219
  return {
178
220
  ok: false,
179
221
  error: `Failed to locate property '${o.memberName}' on '${ifaceName}' in ${internalIndexDtsPath}.\n` +
180
- `This property was annotated with extension wrappers in TS source and should exist in CLR metadata.`,
222
+ `This property was declared in TS source and should exist in CLR metadata.`,
181
223
  };
182
224
  }
183
- const baseType = propMatch[2] ?? "";
184
- const wrappedType = applyWrappersToBaseType(baseType, o.wrappers);
185
- body = body.replace(propRe, `$1${wrappedType}$3`);
225
+ if (getterMatch) {
226
+ const baseType = (o.replaceWithSourceType ? o.sourceTypeText : undefined) ??
227
+ getterMatch[2] ??
228
+ "";
229
+ let nextType = applyWrappersToBaseType(baseType, o.wrappers);
230
+ if (o.isOptional)
231
+ nextType = ensureUndefinedInType(nextType);
232
+ body = body.replace(getterRe, `$1${nextType}$3`);
233
+ }
234
+ if (setterMatch) {
235
+ const baseType = (o.replaceWithSourceType ? o.sourceTypeText : undefined) ??
236
+ setterMatch[2] ??
237
+ "";
238
+ let nextType = applyWrappersToBaseType(baseType, o.wrappers);
239
+ if (o.isOptional)
240
+ nextType = ensureUndefinedInType(nextType);
241
+ body = body.replace(setterRe, `$1${nextType}$3`);
242
+ }
186
243
  }
187
244
  const patchedBlock = head + body + tail;
188
- next = next.slice(0, match.index) + patchedBlock + next.slice(match.index + block.length);
245
+ next =
246
+ next.slice(0, match.index) +
247
+ patchedBlock +
248
+ next.slice(match.index + block.length);
249
+ }
250
+ if (next !== original) {
251
+ writeFileSync(internalIndexDtsPath, next, "utf-8");
252
+ }
253
+ return { ok: true, value: undefined };
254
+ };
255
+ const patchInternalIndexBrandMarkersOptional = (internalIndexDtsPath, typeNames) => {
256
+ if (!existsSync(internalIndexDtsPath)) {
257
+ return {
258
+ ok: false,
259
+ error: `Internal index not found at ${internalIndexDtsPath}`,
260
+ };
261
+ }
262
+ const original = readFileSync(internalIndexDtsPath, "utf-8");
263
+ let next = original;
264
+ for (const typeName of Array.from(new Set(typeNames)).sort((a, b) => a.localeCompare(b))) {
265
+ const ifaceName = `${typeName}$instance`;
266
+ const ifaceRe = new RegExp(String.raw `export\s+interface\s+${escapeRegExp(ifaceName)}\b[^{]*\{[\s\S]*?^\}`, "m");
267
+ const match = ifaceRe.exec(next);
268
+ if (!match || match.index === undefined)
269
+ continue;
270
+ const block = match[0];
271
+ const open = block.indexOf("{");
272
+ const close = block.lastIndexOf("}");
273
+ if (open < 0 || close < 0 || close <= open)
274
+ continue;
275
+ const head = block.slice(0, open + 1);
276
+ let body = block.slice(open + 1, close);
277
+ const tail = block.slice(close);
278
+ const brandRe = /(^\s*readonly\s+__tsonic_type_[A-Za-z0-9_]+)\s*:\s*never\s*;/m;
279
+ if (!brandRe.test(body))
280
+ continue;
281
+ body = body.replace(brandRe, "$1?: never;");
282
+ const patchedBlock = head + body + tail;
283
+ next =
284
+ next.slice(0, match.index) +
285
+ patchedBlock +
286
+ next.slice(match.index + block.length);
189
287
  }
190
288
  if (next !== original) {
191
289
  writeFileSync(internalIndexDtsPath, next, "utf-8");
192
290
  }
193
291
  return { ok: true, value: undefined };
194
292
  };
293
+ const splitTopLevelTypeArgs = (text) => {
294
+ const parts = [];
295
+ let depthAngle = 0;
296
+ let depthParen = 0;
297
+ let depthBrace = 0;
298
+ let depthBracket = 0;
299
+ let start = 0;
300
+ for (let i = 0; i < text.length; i += 1) {
301
+ const ch = text[i];
302
+ if (ch === "<")
303
+ depthAngle += 1;
304
+ else if (ch === ">")
305
+ depthAngle = Math.max(0, depthAngle - 1);
306
+ else if (ch === "(")
307
+ depthParen += 1;
308
+ else if (ch === ")")
309
+ depthParen = Math.max(0, depthParen - 1);
310
+ else if (ch === "{")
311
+ depthBrace += 1;
312
+ else if (ch === "}")
313
+ depthBrace = Math.max(0, depthBrace - 1);
314
+ else if (ch === "[")
315
+ depthBracket += 1;
316
+ else if (ch === "]")
317
+ depthBracket = Math.max(0, depthBracket - 1);
318
+ else if (ch === "," &&
319
+ depthAngle === 0 &&
320
+ depthParen === 0 &&
321
+ depthBrace === 0 &&
322
+ depthBracket === 0) {
323
+ parts.push(text.slice(start, i).trim());
324
+ start = i + 1;
325
+ }
326
+ }
327
+ parts.push(text.slice(start).trim());
328
+ return parts.filter((p) => p.length > 0);
329
+ };
330
+ const expandUnionsDeep = (typeText) => {
331
+ const unionPrefixRe = /Union_\d+</g;
332
+ let result = typeText;
333
+ // Iterate until no more Union_N< patterns remain
334
+ // eslint-disable-next-line no-constant-condition
335
+ while (true) {
336
+ unionPrefixRe.lastIndex = 0;
337
+ const prefixMatch = unionPrefixRe.exec(result);
338
+ if (!prefixMatch)
339
+ break;
340
+ // Find the matching > for the < at the end of the prefix
341
+ const openAngle = prefixMatch.index + prefixMatch[0].length - 1;
342
+ let depth = 1;
343
+ let closeAngle = -1;
344
+ for (let i = openAngle + 1; i < result.length; i += 1) {
345
+ const ch = result[i];
346
+ if (ch === "<")
347
+ depth += 1;
348
+ else if (ch === ">") {
349
+ depth -= 1;
350
+ if (depth === 0) {
351
+ closeAngle = i;
352
+ break;
353
+ }
354
+ }
355
+ }
356
+ if (closeAngle < 0)
357
+ break;
358
+ const inner = result.slice(openAngle + 1, closeAngle);
359
+ const args = splitTopLevelTypeArgs(inner);
360
+ if (args.length < 2)
361
+ break;
362
+ const expanded = `(${args.join(" | ")})`;
363
+ result =
364
+ result.slice(0, prefixMatch.index) +
365
+ expanded +
366
+ result.slice(closeAngle + 1);
367
+ }
368
+ return result;
369
+ };
370
+ const patchFacadeWithSourceFunctionSignatures = (facadeDtsPath, signaturesByName) => {
371
+ if (!existsSync(facadeDtsPath)) {
372
+ return {
373
+ ok: false,
374
+ error: `Facade declaration file not found at ${facadeDtsPath}`,
375
+ };
376
+ }
377
+ const original = readFileSync(facadeDtsPath, "utf-8");
378
+ let next = original;
379
+ for (const [name, signatures] of Array.from(signaturesByName.entries()).sort((a, b) => a[0].localeCompare(b[0]))) {
380
+ if (signatures.length === 0)
381
+ continue;
382
+ const fnRe = new RegExp(String.raw `^(export\s+declare\s+function\s+${escapeRegExp(name)}(?:<[\s\S]*?>)?\s*\([\s\S]*?\)\s*:\s*)([^;]+)(;)`, "m");
383
+ const currentMatch = fnRe.exec(next);
384
+ if (currentMatch) {
385
+ const existingReturnType = currentMatch[2]?.trim() ?? "";
386
+ const replacement = Array.from(new Set(signatures.map((sig) => {
387
+ const returnType = sig.returnTypeText.includes("{")
388
+ ? expandUnionsDeep(existingReturnType)
389
+ : sig.returnTypeText;
390
+ return `export declare function ${name}${sig.typeParametersText}(${sig.parametersText}): ${returnType};`;
391
+ }))).join("\n");
392
+ next = next.replace(fnRe, replacement);
393
+ continue;
394
+ }
395
+ // If no function declaration match, try const Func<...> pattern
396
+ const constFuncRe = new RegExp(String.raw `^export\s+declare\s+const\s+${escapeRegExp(name)}\s*:\s*Func<([\s\S]+?)>\s*;`, "m");
397
+ const constMatch = constFuncRe.exec(next);
398
+ if (!constMatch || !constMatch[1])
399
+ continue;
400
+ const funcTypeArgs = splitTopLevelTypeArgs(constMatch[1]);
401
+ if (funcTypeArgs.length < 2)
402
+ continue;
403
+ // Last arg = return type, remaining args = parameter types
404
+ const facadeParamTypes = funcTypeArgs.slice(0, -1);
405
+ const facadeReturnType = funcTypeArgs[funcTypeArgs.length - 1];
406
+ // Use the first source signature for parameter names
407
+ const sourceSig = signatures[0];
408
+ const sourceParams = sourceSig.parametersText
409
+ .split(",")
410
+ .map((p) => p.trim())
411
+ .filter((p) => p.length > 0);
412
+ // If count mismatch, skip patching for this declaration
413
+ if (sourceParams.length !== facadeParamTypes.length)
414
+ continue;
415
+ // Pair source parameter NAMES with facade parameter TYPES
416
+ const pairedParams = sourceParams.map((param, idx) => {
417
+ const colonIdx = param.indexOf(":");
418
+ const paramName = colonIdx >= 0 ? param.slice(0, colonIdx).trim() : param.trim();
419
+ return `${paramName}: ${facadeParamTypes[idx]}`;
420
+ });
421
+ const expandedReturnType = expandUnionsDeep(facadeReturnType);
422
+ const typeParamsText = sourceSig.typeParametersText;
423
+ const replacement = `export declare function ${name}${typeParamsText}(${pairedParams.join(", ")}): ${expandedReturnType};`;
424
+ next = next.replace(constFuncRe, replacement);
425
+ }
426
+ if (next !== original) {
427
+ writeFileSync(facadeDtsPath, next, "utf-8");
428
+ }
429
+ return { ok: true, value: undefined };
430
+ };
195
431
  const classifyExportKind = (module, name) => {
196
432
  const isNamed = (stmt) => typeof stmt.name === "string";
197
433
  const findDecl = () => {
198
434
  for (const stmt of module.body) {
199
- if (!("isExported" in stmt) || stmt.isExported !== true)
435
+ if (!("isExported" in stmt) ||
436
+ stmt.isExported !== true)
200
437
  continue;
201
438
  if (isNamed(stmt) && stmt.name === name)
202
439
  return stmt;
@@ -256,7 +493,10 @@ const resolveLocalModuleFile = (fromModule, fromFile, modulesByFile) => {
256
493
  };
257
494
  const buildModuleSourceIndex = (absoluteFilePath, fileKey) => {
258
495
  if (!existsSync(absoluteFilePath)) {
259
- return { ok: false, error: `Failed to read source file for bindings augmentation: ${absoluteFilePath}` };
496
+ return {
497
+ ok: false,
498
+ error: `Failed to read source file for bindings augmentation: ${absoluteFilePath}`,
499
+ };
260
500
  }
261
501
  const content = readFileSync(absoluteFilePath, "utf-8");
262
502
  const scriptKind = absoluteFilePath.endsWith(".tsx")
@@ -268,13 +508,26 @@ const buildModuleSourceIndex = (absoluteFilePath, fileKey) => {
268
508
  const wrapperImportsByLocalName = new Map();
269
509
  const typeImportsByLocalName = new Map();
270
510
  const typeAliasesByName = new Map();
511
+ const exportedFunctionSignaturesByName = new Map();
271
512
  const memberTypesByClassAndMember = new Map();
272
- const getMemberName = (name) => {
273
- if (ts.isIdentifier(name))
274
- return name.text;
275
- if (ts.isStringLiteral(name) || ts.isNumericLiteral(name))
276
- return name.text;
277
- return undefined;
513
+ const printTypeParametersText = (typeParameters) => {
514
+ if (!typeParameters || typeParameters.length === 0)
515
+ return "";
516
+ return `<${typeParameters.map((tp) => tp.getText(sourceFile)).join(", ")}>`;
517
+ };
518
+ const printParameterText = (param) => {
519
+ const rest = param.dotDotDotToken ? "..." : "";
520
+ const name = param.name.getText(sourceFile);
521
+ const optional = param.questionToken ? "?" : "";
522
+ const type = param.type
523
+ ? printTypeNodeText(param.type, sourceFile)
524
+ : "unknown";
525
+ return `${rest}${name}${optional}: ${type}`;
526
+ };
527
+ const addExportedFunctionSignature = (name, sig) => {
528
+ const list = exportedFunctionSignaturesByName.get(name) ?? [];
529
+ list.push(sig);
530
+ exportedFunctionSignaturesByName.set(name, list);
278
531
  };
279
532
  for (const stmt of sourceFile.statements) {
280
533
  if (ts.isImportDeclaration(stmt)) {
@@ -295,9 +548,15 @@ const buildModuleSourceIndex = (absoluteFilePath, fileKey) => {
295
548
  const isTypeOnly = clause.isTypeOnly || spec.isTypeOnly;
296
549
  if (!isTypeOnly)
297
550
  continue;
298
- typeImportsByLocalName.set(localName, { source: moduleSpecifier, importedName });
551
+ typeImportsByLocalName.set(localName, {
552
+ source: moduleSpecifier,
553
+ importedName,
554
+ });
299
555
  if (importedName === "ExtensionMethods") {
300
- wrapperImportsByLocalName.set(localName, { source: moduleSpecifier, importedName });
556
+ wrapperImportsByLocalName.set(localName, {
557
+ source: moduleSpecifier,
558
+ importedName,
559
+ });
301
560
  }
302
561
  }
303
562
  continue;
@@ -308,31 +567,102 @@ const buildModuleSourceIndex = (absoluteFilePath, fileKey) => {
308
567
  typeAliasesByName.set(aliasName, { typeParameters, type: stmt.type });
309
568
  continue;
310
569
  }
570
+ if (ts.isFunctionDeclaration(stmt)) {
571
+ const hasExport = stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
572
+ if (!hasExport || !stmt.name || !stmt.type)
573
+ continue;
574
+ const parametersText = stmt.parameters.map(printParameterText).join(", ");
575
+ addExportedFunctionSignature(stmt.name.text, {
576
+ typeParametersText: printTypeParametersText(stmt.typeParameters),
577
+ parametersText,
578
+ returnTypeText: printTypeNodeText(stmt.type, sourceFile),
579
+ });
580
+ continue;
581
+ }
582
+ if (ts.isVariableStatement(stmt)) {
583
+ const hasExport = stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
584
+ if (!hasExport)
585
+ continue;
586
+ for (const decl of stmt.declarationList.declarations) {
587
+ if (!ts.isIdentifier(decl.name))
588
+ continue;
589
+ const exportName = decl.name.text;
590
+ const init = decl.initializer;
591
+ if (!init)
592
+ continue;
593
+ if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) {
594
+ const returnType = init.type;
595
+ if (!returnType)
596
+ continue;
597
+ const parametersText = init.parameters
598
+ .map(printParameterText)
599
+ .join(", ");
600
+ addExportedFunctionSignature(exportName, {
601
+ typeParametersText: printTypeParametersText(init.typeParameters),
602
+ parametersText,
603
+ returnTypeText: printTypeNodeText(returnType, sourceFile),
604
+ });
605
+ }
606
+ }
607
+ continue;
608
+ }
311
609
  if (ts.isClassDeclaration(stmt) && stmt.name) {
312
610
  const className = stmt.name.text;
313
- const members = memberTypesByClassAndMember.get(className) ?? new Map();
611
+ const members = memberTypesByClassAndMember.get(className) ??
612
+ new Map();
314
613
  for (const member of stmt.members) {
315
614
  if (ts.isGetAccessorDeclaration(member)) {
316
615
  if (!member.name || !member.type)
317
616
  continue;
318
- const name = getMemberName(member.name);
617
+ const name = getPropertyNameText(member.name);
319
618
  if (!name)
320
619
  continue;
321
- members.set(name, member.type);
620
+ members.set(name, {
621
+ typeNode: member.type,
622
+ typeText: printTypeNodeText(member.type, sourceFile),
623
+ isOptional: false,
624
+ });
322
625
  continue;
323
626
  }
324
627
  if (ts.isPropertyDeclaration(member)) {
325
628
  if (!member.name || !member.type)
326
629
  continue;
327
- const name = getMemberName(member.name);
630
+ const name = getPropertyNameText(member.name);
328
631
  if (!name)
329
632
  continue;
330
- members.set(name, member.type);
633
+ members.set(name, {
634
+ typeNode: member.type,
635
+ typeText: printTypeNodeText(member.type, sourceFile),
636
+ isOptional: member.questionToken !== undefined,
637
+ });
331
638
  }
332
639
  }
333
640
  if (members.size > 0) {
334
641
  memberTypesByClassAndMember.set(className, members);
335
642
  }
643
+ continue;
644
+ }
645
+ if (ts.isInterfaceDeclaration(stmt)) {
646
+ const interfaceName = stmt.name.text;
647
+ const members = memberTypesByClassAndMember.get(interfaceName) ??
648
+ new Map();
649
+ for (const member of stmt.members) {
650
+ if (!ts.isPropertySignature(member))
651
+ continue;
652
+ if (!member.name || !member.type)
653
+ continue;
654
+ const name = getPropertyNameText(member.name);
655
+ if (!name)
656
+ continue;
657
+ members.set(name, {
658
+ typeNode: member.type,
659
+ typeText: printTypeNodeText(member.type, sourceFile),
660
+ isOptional: member.questionToken !== undefined,
661
+ });
662
+ }
663
+ if (members.size > 0) {
664
+ memberTypesByClassAndMember.set(interfaceName, members);
665
+ }
336
666
  }
337
667
  }
338
668
  return {
@@ -342,10 +672,27 @@ const buildModuleSourceIndex = (absoluteFilePath, fileKey) => {
342
672
  wrapperImportsByLocalName,
343
673
  typeImportsByLocalName,
344
674
  typeAliasesByName,
675
+ exportedFunctionSignaturesByName,
345
676
  memberTypesByClassAndMember,
346
677
  },
347
678
  };
348
679
  };
680
+ const typeNodeUsesImportedTypeNames = (node, typeImportsByLocalName) => {
681
+ let found = false;
682
+ const visit = (current) => {
683
+ if (found)
684
+ return;
685
+ if (ts.isTypeReferenceNode(current) && ts.isIdentifier(current.typeName)) {
686
+ if (typeImportsByLocalName.has(current.typeName.text)) {
687
+ found = true;
688
+ return;
689
+ }
690
+ }
691
+ ts.forEachChild(current, visit);
692
+ };
693
+ visit(node);
694
+ return found;
695
+ };
349
696
  const unwrapParens = (node) => {
350
697
  let current = node;
351
698
  while (ts.isParenthesizedTypeNode(current)) {
@@ -399,7 +746,8 @@ const collectExtensionWrapperImportsFromSourceType = (opts) => {
399
746
  continue;
400
747
  }
401
748
  const imported = info.typeImportsByLocalName.get(ident);
402
- if (imported && (imported.source.startsWith(".") || imported.source.startsWith("/"))) {
749
+ if (imported &&
750
+ (imported.source.startsWith(".") || imported.source.startsWith("/"))) {
403
751
  const targetModule = resolveLocalModuleFile(imported.source, currentModuleKey, opts.modulesByFileKey);
404
752
  if (targetModule) {
405
753
  const targetKey = normalizeModuleFileKey(targetModule.filePath);
@@ -453,7 +801,9 @@ const printIrType = (type, ctx) => {
453
801
  case "primitiveType":
454
802
  return type.name;
455
803
  case "literalType":
456
- return typeof type.value === "string" ? JSON.stringify(type.value) : String(type.value);
804
+ return typeof type.value === "string"
805
+ ? JSON.stringify(type.value)
806
+ : String(type.value);
457
807
  case "anyType":
458
808
  return "any";
459
809
  case "unknownType":
@@ -469,7 +819,9 @@ const printIrType = (type, ctx) => {
469
819
  const args = type.typeArguments ?? [];
470
820
  if (args.length === 0)
471
821
  return base;
472
- const rendered = args.map((a) => printIrType(a, { parentPrecedence: 0 })).join(", ");
822
+ const rendered = args
823
+ .map((a) => printIrType(a, { parentPrecedence: 0 }))
824
+ .join(", ");
473
825
  return `${base}<${rendered}>`;
474
826
  }
475
827
  case "arrayType":
@@ -484,7 +836,9 @@ const printIrType = (type, ctx) => {
484
836
  return p.pattern.name;
485
837
  return `p${i + 1}`;
486
838
  })();
487
- const t = p.type ? printIrType(p.type, { parentPrecedence: 0 }) : "unknown";
839
+ const t = p.type
840
+ ? printIrType(p.type, { parentPrecedence: 0 })
841
+ : "unknown";
488
842
  return `${name}: ${t}`;
489
843
  })
490
844
  .join(", ");
@@ -492,11 +846,15 @@ const printIrType = (type, ctx) => {
492
846
  return wrap(`(${ps}) => ${ret}`, 2);
493
847
  }
494
848
  case "unionType": {
495
- const rendered = type.types.map((t) => printIrType(t, { parentPrecedence: 0 })).join(" | ");
849
+ const rendered = type.types
850
+ .map((t) => printIrType(t, { parentPrecedence: 0 }))
851
+ .join(" | ");
496
852
  return wrap(rendered, 0);
497
853
  }
498
854
  case "intersectionType": {
499
- const rendered = type.types.map((t) => printIrType(t, { parentPrecedence: 1 })).join(" & ");
855
+ const rendered = type.types
856
+ .map((t) => printIrType(t, { parentPrecedence: 1 }))
857
+ .join(" & ");
500
858
  return wrap(rendered, 1);
501
859
  }
502
860
  case "dictionaryType": {
@@ -504,10 +862,40 @@ const printIrType = (type, ctx) => {
504
862
  const v = printIrType(type.valueType, { parentPrecedence: 0 });
505
863
  return `Record<${k}, ${v}>`;
506
864
  }
507
- case "objectType":
508
- // Object type aliases are materialized as __Alias CLR types in source builds.
509
- // If we reach here, the alias printer should have handled it separately.
510
- return "{ /* object */ }";
865
+ case "objectType": {
866
+ if (type.members.length === 0)
867
+ return "{}";
868
+ const members = type.members
869
+ .map((member) => {
870
+ if (member.kind === "propertySignature") {
871
+ const readonly = member.isReadonly ? "readonly " : "";
872
+ const optional = member.isOptional ? "?" : "";
873
+ const memberType = printIrType(member.type, {
874
+ parentPrecedence: 0,
875
+ });
876
+ return `${readonly}${member.name}${optional}: ${memberType}`;
877
+ }
878
+ const typeParams = printTypeParameters(member.typeParameters);
879
+ const args = member.parameters
880
+ .map((p, i) => {
881
+ const name = p.pattern.kind === "identifierPattern"
882
+ ? p.pattern.name
883
+ : `p${i + 1}`;
884
+ const optional = p.isOptional ? "?" : "";
885
+ const paramType = p.type
886
+ ? printIrType(p.type, { parentPrecedence: 0 })
887
+ : "unknown";
888
+ return `${name}${optional}: ${paramType}`;
889
+ })
890
+ .join(", ");
891
+ const returnType = member.returnType
892
+ ? printIrType(member.returnType, { parentPrecedence: 0 })
893
+ : "void";
894
+ return `${member.name}${typeParams}(${args}): ${returnType}`;
895
+ })
896
+ .join("; ");
897
+ return `{ ${members} }`;
898
+ }
511
899
  default:
512
900
  // Exhaustiveness safety
513
901
  return "unknown";
@@ -529,11 +917,74 @@ const renderExportedTypeAlias = (stmt, internalIndexDts) => {
529
917
  const typeArgs = stmt.typeParameters && stmt.typeParameters.length > 0
530
918
  ? `<${stmt.typeParameters.map((tp) => tp.name).join(", ")}>`
531
919
  : "";
532
- return { ok: true, value: `export type ${stmt.name}${typeParams} = Internal.${internalName}${typeArgs};` };
920
+ return {
921
+ ok: true,
922
+ value: `export type ${stmt.name}${typeParams} = Internal.${internalName}${typeArgs};`,
923
+ };
533
924
  }
534
925
  const rhs = printIrType(stmt.type, { parentPrecedence: 0 });
535
926
  return { ok: true, value: `export type ${stmt.name}${typeParams} = ${rhs};` };
536
927
  };
928
+ /**
929
+ * Overlay already-augmented bindings from dependency assemblies.
930
+ *
931
+ * When a library references sibling Tsonic-built libraries (via references.libraries),
932
+ * tsbindgen regenerates types from CLR metadata, losing source-level augmentation
933
+ * (literal types, optional markers, brand optionality, etc.). The dependency's published
934
+ * bindings already have this augmentation applied, so we overlay them onto the
935
+ * freshly-generated copies.
936
+ */
937
+ export const overlayDependencyBindings = (config, bindingsOutDir) => {
938
+ const depBindingsDirByAssembly = new Map();
939
+ for (const lib of config.libraries) {
940
+ if (!lib.toLowerCase().endsWith(".dll"))
941
+ continue;
942
+ const assemblyName = basename(lib, ".dll");
943
+ // Skip the current package's own assembly.
944
+ if (assemblyName === config.outputName)
945
+ continue;
946
+ // Convention: DLL at <project>/dist/<dotnetVersion>/<name>.dll,
947
+ // bindings at <project>/dist/tsonic/bindings/.
948
+ const depBindingsDir = join(dirname(dirname(lib)), "tsonic", "bindings");
949
+ if (existsSync(depBindingsDir)) {
950
+ depBindingsDirByAssembly.set(assemblyName, depBindingsDir);
951
+ }
952
+ }
953
+ if (depBindingsDirByAssembly.size === 0) {
954
+ return { ok: true, value: undefined };
955
+ }
956
+ // Scan generated bindings for namespace directories with internal/index.d.ts.
957
+ const generatedNamespaces = readdirSync(bindingsOutDir, {
958
+ withFileTypes: true,
959
+ })
960
+ .filter((e) => e.isDirectory())
961
+ .map((e) => e.name);
962
+ for (const ns of generatedNamespaces) {
963
+ const internalIndexPath = join(bindingsOutDir, ns, "internal", "index.d.ts");
964
+ if (!existsSync(internalIndexPath))
965
+ continue;
966
+ const content = readFileSync(internalIndexPath, "utf-8");
967
+ const assemblyMatch = content.match(/^\/\/ Assembly:\s*(.+)\s*$/m);
968
+ if (!assemblyMatch || !assemblyMatch[1])
969
+ continue;
970
+ const assembly = assemblyMatch[1].trim();
971
+ const depDir = depBindingsDirByAssembly.get(assembly);
972
+ if (!depDir)
973
+ continue;
974
+ // Overlay the dependency's already-augmented internal/index.d.ts.
975
+ const depInternalIndex = join(depDir, ns, "internal", "index.d.ts");
976
+ if (existsSync(depInternalIndex)) {
977
+ copyFileSync(depInternalIndex, internalIndexPath);
978
+ }
979
+ // Overlay the dependency's facade .d.ts (may have type aliases, re-exports).
980
+ const facadeDts = join(bindingsOutDir, `${ns}.d.ts`);
981
+ const depFacadeDts = join(depDir, `${ns}.d.ts`);
982
+ if (existsSync(facadeDts) && existsSync(depFacadeDts)) {
983
+ copyFileSync(depFacadeDts, facadeDts);
984
+ }
985
+ }
986
+ return { ok: true, value: undefined };
987
+ };
537
988
  export const augmentLibraryBindingsFromSource = (config, bindingsOutDir) => {
538
989
  const entryPoint = config.entryPoint;
539
990
  if (!entryPoint) {
@@ -552,7 +1003,10 @@ export const augmentLibraryBindingsFromSource = (config, bindingsOutDir) => {
552
1003
  };
553
1004
  const graphResult = buildModuleDependencyGraph(absoluteEntryPoint, compilerOptions);
554
1005
  if (!graphResult.ok) {
555
- return { ok: false, error: `Failed to analyze library sources:\n${renderDiagnostics(graphResult.error)}` };
1006
+ return {
1007
+ ok: false,
1008
+ error: `Failed to analyze library sources:\n${renderDiagnostics(graphResult.error)}`,
1009
+ };
556
1010
  }
557
1011
  const { modules, entryModule } = graphResult.value;
558
1012
  const facadesByNamespace = new Map(indexFacadeFiles(bindingsOutDir));
@@ -661,8 +1115,10 @@ export const augmentLibraryBindingsFromSource = (config, bindingsOutDir) => {
661
1115
  `Could not find an exported declaration named '${exp.originalName}' in ${targetModule.filePath}.`,
662
1116
  };
663
1117
  }
1118
+ const spec = exp.name === exp.originalName
1119
+ ? exp.name
1120
+ : `${exp.originalName} as ${exp.name}`;
664
1121
  const isTypeOnly = kind === "type";
665
- const spec = exp.name === exp.originalName ? exp.name : `${exp.originalName} as ${exp.name}`;
666
1122
  const key = `${targetFacade.moduleSpecifier}|${isTypeOnly ? "type" : "value"}`;
667
1123
  const list = grouped.get(key) ?? [];
668
1124
  list.push(spec);
@@ -697,13 +1153,20 @@ export const augmentLibraryBindingsFromSource = (config, bindingsOutDir) => {
697
1153
  writeFileSync(entryFacade.facadeJsPath, next, "utf-8");
698
1154
  }
699
1155
  }
700
- // 3) Preserve TS-authored extension wrapper annotations on exported class members.
1156
+ // 3) Preserve TS-authored member typing semantics on exported class/interface members.
701
1157
  // These wrapper types (ExtensionMethods<...>) do not exist in CLR metadata and therefore
702
1158
  // cannot be discovered by tsbindgen when generating bindings from the DLL. We can,
703
1159
  // however, safely re-apply them for Tsonic-authored libraries by reading the TS source
704
- // graph and wrapping the CLR base member type in the published internal/index.d.ts.
1160
+ // graph and patching the published internal/index.d.ts:
1161
+ // - Re-apply ExtensionMethods wrappers (class + interface members)
1162
+ // - Preserve optional (`?`) semantics by allowing `undefined` on patched members
1163
+ // - For exported interfaces, preserve source structural member types when safe
705
1164
  const sourceIndexByFileKey = new Map();
706
1165
  for (const m of modules) {
1166
+ // Synthetic IR modules (e.g., program-wide anonymous type declarations) do not
1167
+ // correspond to real source files and must be ignored by source-based augmentation.
1168
+ if (m.filePath.startsWith("__tsonic/"))
1169
+ continue;
707
1170
  const key = normalizeModuleFileKey(m.filePath);
708
1171
  const absolutePath = resolve(absoluteSourceRoot, key);
709
1172
  const indexed = buildModuleSourceIndex(absolutePath, key);
@@ -712,15 +1175,35 @@ export const augmentLibraryBindingsFromSource = (config, bindingsOutDir) => {
712
1175
  sourceIndexByFileKey.set(key, indexed.value);
713
1176
  }
714
1177
  const overridesByInternalIndex = new Map();
1178
+ const brandOptionalTypesByInternalIndex = new Map();
1179
+ const functionSignaturesByFacade = new Map();
715
1180
  for (const m of modules) {
716
- const exportedClasses = m.body.filter((s) => s.kind === "classDeclaration" && s.isExported);
717
- if (exportedClasses.length === 0)
1181
+ if (m.filePath.startsWith("__tsonic/"))
718
1182
  continue;
1183
+ const exportedClasses = m.body.filter((s) => s.kind === "classDeclaration" && s.isExported);
1184
+ const exportedInterfaces = m.body.filter((s) => s.kind === "interfaceDeclaration" && s.isExported);
1185
+ const exportedAliases = m.body.filter((s) => s.kind === "typeAliasDeclaration" && s.isExported);
719
1186
  const moduleKey = normalizeModuleFileKey(m.filePath);
720
1187
  const sourceIndex = sourceIndexByFileKey.get(moduleKey);
721
1188
  if (!sourceIndex)
722
1189
  continue;
1190
+ const hasExportedSourceFunctions = sourceIndex.exportedFunctionSignaturesByName.size > 0;
1191
+ if (exportedClasses.length === 0 &&
1192
+ exportedInterfaces.length === 0 &&
1193
+ exportedAliases.length === 0 &&
1194
+ !hasExportedSourceFunctions)
1195
+ continue;
723
1196
  const info = facadesByNamespace.get(m.namespace) ?? ensureFacade(m.namespace);
1197
+ for (const [name, signatures,] of sourceIndex.exportedFunctionSignaturesByName) {
1198
+ if (signatures.length === 0)
1199
+ continue;
1200
+ const byName = functionSignaturesByFacade.get(info.facadeDtsPath) ??
1201
+ new Map();
1202
+ const list = byName.get(name) ?? [];
1203
+ list.push(...signatures);
1204
+ byName.set(name, list);
1205
+ functionSignaturesByFacade.set(info.facadeDtsPath, byName);
1206
+ }
724
1207
  for (const cls of exportedClasses) {
725
1208
  const memberTypes = sourceIndex.memberTypesByClassAndMember.get(cls.name);
726
1209
  if (!memberTypes)
@@ -732,25 +1215,115 @@ export const augmentLibraryBindingsFromSource = (config, bindingsOutDir) => {
732
1215
  continue;
733
1216
  if (member.accessibility === "private")
734
1217
  continue;
735
- const annotatedType = memberTypes.get(member.name);
736
- if (!annotatedType)
1218
+ const sourceMember = memberTypes.get(member.name);
1219
+ if (!sourceMember)
737
1220
  continue;
738
1221
  const wrappersResult = collectExtensionWrapperImportsFromSourceType({
739
1222
  startModuleKey: moduleKey,
740
- typeNode: annotatedType,
1223
+ typeNode: sourceMember.typeNode,
741
1224
  sourceIndexByFileKey,
742
1225
  modulesByFileKey: modulesByFile,
743
1226
  });
744
1227
  if (!wrappersResult.ok)
745
1228
  return wrappersResult;
746
1229
  const wrappers = wrappersResult.value;
747
- if (wrappers.length === 0)
1230
+ if (wrappers.length === 0 && !sourceMember.isOptional)
748
1231
  continue;
749
1232
  const list = overridesByInternalIndex.get(info.internalIndexDtsPath) ?? [];
750
1233
  list.push({
751
1234
  namespace: m.namespace,
752
1235
  className: cls.name,
753
1236
  memberName: member.name,
1237
+ isOptional: sourceMember.isOptional,
1238
+ wrappers,
1239
+ });
1240
+ overridesByInternalIndex.set(info.internalIndexDtsPath, list);
1241
+ }
1242
+ }
1243
+ for (const iface of exportedInterfaces) {
1244
+ const memberTypes = sourceIndex.memberTypesByClassAndMember.get(iface.name);
1245
+ if (!memberTypes)
1246
+ continue;
1247
+ for (const member of iface.members) {
1248
+ if (member.kind !== "propertySignature")
1249
+ continue;
1250
+ const sourceMember = memberTypes.get(member.name);
1251
+ if (!sourceMember)
1252
+ continue;
1253
+ const wrappersResult = collectExtensionWrapperImportsFromSourceType({
1254
+ startModuleKey: moduleKey,
1255
+ typeNode: sourceMember.typeNode,
1256
+ sourceIndexByFileKey,
1257
+ modulesByFileKey: modulesByFile,
1258
+ });
1259
+ if (!wrappersResult.ok)
1260
+ return wrappersResult;
1261
+ const wrappers = wrappersResult.value;
1262
+ const canUseSourceTypeText = !typeNodeUsesImportedTypeNames(sourceMember.typeNode, sourceIndex.typeImportsByLocalName);
1263
+ if (!canUseSourceTypeText && wrappers.length === 0)
1264
+ continue;
1265
+ const list = overridesByInternalIndex.get(info.internalIndexDtsPath) ?? [];
1266
+ list.push({
1267
+ namespace: m.namespace,
1268
+ className: iface.name,
1269
+ memberName: member.name,
1270
+ sourceTypeText: canUseSourceTypeText
1271
+ ? sourceMember.typeText
1272
+ : undefined,
1273
+ replaceWithSourceType: canUseSourceTypeText,
1274
+ isOptional: sourceMember.isOptional,
1275
+ wrappers,
1276
+ });
1277
+ overridesByInternalIndex.set(info.internalIndexDtsPath, list);
1278
+ }
1279
+ const brandTargets = brandOptionalTypesByInternalIndex.get(info.internalIndexDtsPath) ??
1280
+ new Set();
1281
+ brandTargets.add(iface.name);
1282
+ brandOptionalTypesByInternalIndex.set(info.internalIndexDtsPath, brandTargets);
1283
+ }
1284
+ for (const alias of exportedAliases) {
1285
+ const sourceAlias = sourceIndex.typeAliasesByName.get(alias.name);
1286
+ if (!sourceAlias)
1287
+ continue;
1288
+ const aliasType = unwrapParens(sourceAlias.type);
1289
+ if (!ts.isTypeLiteralNode(aliasType))
1290
+ continue;
1291
+ const arity = sourceAlias.typeParameters.length;
1292
+ const internalAliasName = `${alias.name}__Alias${arity > 0 ? `_${arity}` : ""}`;
1293
+ const brandTargets = brandOptionalTypesByInternalIndex.get(info.internalIndexDtsPath) ??
1294
+ new Set();
1295
+ brandTargets.add(internalAliasName);
1296
+ brandOptionalTypesByInternalIndex.set(info.internalIndexDtsPath, brandTargets);
1297
+ for (const member of aliasType.members) {
1298
+ if (!ts.isPropertySignature(member))
1299
+ continue;
1300
+ if (!member.name || !member.type)
1301
+ continue;
1302
+ const memberName = getPropertyNameText(member.name);
1303
+ if (!memberName)
1304
+ continue;
1305
+ const wrappersResult = collectExtensionWrapperImportsFromSourceType({
1306
+ startModuleKey: moduleKey,
1307
+ typeNode: member.type,
1308
+ sourceIndexByFileKey,
1309
+ modulesByFileKey: modulesByFile,
1310
+ });
1311
+ if (!wrappersResult.ok)
1312
+ return wrappersResult;
1313
+ const wrappers = wrappersResult.value;
1314
+ const canUseSourceTypeText = !typeNodeUsesImportedTypeNames(member.type, sourceIndex.typeImportsByLocalName);
1315
+ if (!canUseSourceTypeText && wrappers.length === 0)
1316
+ continue;
1317
+ const list = overridesByInternalIndex.get(info.internalIndexDtsPath) ?? [];
1318
+ list.push({
1319
+ namespace: m.namespace,
1320
+ className: internalAliasName,
1321
+ memberName,
1322
+ sourceTypeText: canUseSourceTypeText
1323
+ ? printTypeNodeText(member.type, member.getSourceFile())
1324
+ : undefined,
1325
+ replaceWithSourceType: canUseSourceTypeText,
1326
+ isOptional: member.questionToken !== undefined,
754
1327
  wrappers,
755
1328
  });
756
1329
  overridesByInternalIndex.set(info.internalIndexDtsPath, list);
@@ -762,6 +1335,16 @@ export const augmentLibraryBindingsFromSource = (config, bindingsOutDir) => {
762
1335
  if (!result.ok)
763
1336
  return result;
764
1337
  }
1338
+ for (const [internalIndex, typeNames] of brandOptionalTypesByInternalIndex) {
1339
+ const result = patchInternalIndexBrandMarkersOptional(internalIndex, Array.from(typeNames.values()));
1340
+ if (!result.ok)
1341
+ return result;
1342
+ }
1343
+ for (const [facadePath, signaturesByName] of functionSignaturesByFacade) {
1344
+ const result = patchFacadeWithSourceFunctionSignatures(facadePath, signaturesByName);
1345
+ if (!result.ok)
1346
+ return result;
1347
+ }
765
1348
  return { ok: true, value: undefined };
766
1349
  };
767
1350
  //# sourceMappingURL=library-bindings-augment.js.map