@boperators/mcp-server 0.2.1 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +6 -6
  2. package/dist/index.js +165 -298
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -22,7 +22,7 @@ bun add -D @boperators/mcp-server
22
22
  |------|-------------|:-------------------:|
23
23
  | [`list_overloads`](#list_overloads) | List all registered overloads in the project, with optional filtering by class or operator | ✓ |
24
24
  | [`transform_preview`](#transform_preview) | Preview the transformed output for a file or a line range within it | ✓ |
25
- | [`scaffold_overloads`](#scaffold_overloads) | Generate `as const` boilerplate for a set of operators on a named class | — |
25
+ | [`scaffold_overloads`](#scaffold_overloads) | Generate method boilerplate for a set of operators on a named class | — |
26
26
  | [`validate_overloads`](#validate_overloads) | Validate overload definitions in a single file and return structured diagnostics | ✓ |
27
27
  | [`explain_expression`](#explain_expression) | Reverse-engineer a transformed call expression back to its original operator and overload metadata | optional |
28
28
 
@@ -57,11 +57,11 @@ Transforms a file and returns the original and transformed text side by side, al
57
57
 
58
58
  ### `scaffold_overloads`
59
59
 
60
- Generates ready-to-paste TypeScript property declarations for a list of operators on a given class. Automatically uses the correct form for each operator:
60
+ Generates ready-to-paste TypeScript method declarations for a list of operators on a given class. Automatically uses the correct form for each operator:
61
61
 
62
- - **Static binary** (`+`, `-`, `*`, …) — `static readonly "+" = [(a: T, b: T): T => { … }] as const`
62
+ - **Static binary** (`+`, `-`, `*`, …) — `static "+"(a: T, b: T): T { … }`
63
63
  - **Comparison** (`>`, `==`, …) — static, returns `boolean`
64
- - **Instance compound** (`+=`, `-=`, …) — instance, `function(this: T, rhs: T): void`
64
+ - **Instance compound** (`+=`, `-=`, …) — instance, `"+="(rhs: T): void { … }`
65
65
  - **Prefix unary** (`!`, `~`) — static, one parameter
66
66
  - **Postfix unary** (`++`, `--`) — instance, no parameters, returns `void`
67
67
 
@@ -80,7 +80,7 @@ Does not require a `tsconfig` — it is purely generative.
80
80
 
81
81
  Runs the boperators scanning pipeline against a single file in isolation and returns structured diagnostics without modifying any state. Reports:
82
82
 
83
- - **Errors** — wrong arity, missing `as const`, return type violations
83
+ - **Errors** — wrong arity, return type violations
84
84
  - **Warnings** — duplicate/conflicting overload registrations
85
85
  - The count of successfully parsed overloads
86
86
 
@@ -95,7 +95,7 @@ Runs the boperators scanning pipeline against a single file in isolation and ret
95
95
 
96
96
  ### `explain_expression`
97
97
 
98
- Given a transformed boperators expression (e.g. `Vector3["+"][0](a, b)` or `v["+="][0].call(v, rhs)`), decodes it back to the original operator, identifies whether it is static/instance and binary/unary, and optionally enriches the result with metadata from the project's overload store.
98
+ Given a transformed boperators expression (e.g. `Vector3["+"](a, b)` or `v["+="](rhs)` or `v["++"]( )`), decodes it back to the original operator, identifies whether it is static/instance and binary/unary, and optionally enriches the result with metadata from the project's overload store.
99
99
 
100
100
  **Inputs**
101
101
 
package/dist/index.js CHANGED
@@ -248869,6 +248869,29 @@ Node text: ${this.#forgottenText}`;
248869
248869
  exports.setScopeForNode = setScopeForNode;
248870
248870
  });
248871
248871
 
248872
+ // ../package/dist/core/helpers/getOperatorStringFromMethod.js
248873
+ var require_getOperatorStringFromMethod = __commonJS((exports) => {
248874
+ Object.defineProperty(exports, "__esModule", { value: true });
248875
+ exports.getOperatorStringFromMethod = getOperatorStringFromMethod;
248876
+ var ts_morph_1 = require_ts_morph();
248877
+ function getOperatorStringFromMethod(method) {
248878
+ const nameNode = method.getNameNode();
248879
+ if (nameNode.isKind(ts_morph_1.SyntaxKind.ComputedPropertyName)) {
248880
+ const expression = nameNode.getExpression();
248881
+ if (expression.isKind(ts_morph_1.SyntaxKind.StringLiteral)) {
248882
+ return expression.getLiteralValue();
248883
+ }
248884
+ const literalValue = expression.getType().getLiteralValue();
248885
+ if (typeof literalValue === "string") {
248886
+ return literalValue;
248887
+ }
248888
+ } else if (nameNode.isKind(ts_morph_1.SyntaxKind.StringLiteral)) {
248889
+ return nameNode.getLiteralValue();
248890
+ }
248891
+ return;
248892
+ }
248893
+ });
248894
+
248872
248895
  // ../package/dist/core/helpers/getOperatorStringFromProperty.js
248873
248896
  var require_getOperatorStringFromProperty = __commonJS((exports) => {
248874
248897
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -249298,7 +249321,7 @@ var require_OverloadInjector = __commonJS((exports) => {
249298
249321
  const overloadDesc = this._overloadStore.findOverload(operatorKind, leftType, rightType);
249299
249322
  if (!overloadDesc)
249300
249323
  continue;
249301
- const { className: classNameRaw, classFilePath, operatorString, index, isStatic } = overloadDesc;
249324
+ const { className: classNameRaw, classFilePath, operatorString, isStatic } = overloadDesc;
249302
249325
  const classSourceFile = this._project.getSourceFileOrThrow(classFilePath);
249303
249326
  const classDecl = classSourceFile.getClassOrThrow(classNameRaw);
249304
249327
  const classSymbol = classDecl.getSymbol();
@@ -249306,7 +249329,7 @@ var require_OverloadInjector = __commonJS((exports) => {
249306
249329
  throw new Error(`No symbol for class "${classNameRaw}"`);
249307
249330
  const classModuleSpecifier = (0, getModuleSpecifier_1.getModuleSpecifier)(sourceFile, classSourceFile);
249308
249331
  const className = (0, ensureImportedName_1.ensureImportedName)(sourceFile, classSymbol, classModuleSpecifier);
249309
- const overloadCall = isStatic ? `${className}["${operatorString}"][${index}](${lhs.getText()}, ${rhs.getText()})` : `${lhs.getText()}["${operatorString}"][${index}].call(${lhs.getText()}, ${rhs.getText()})`;
249332
+ const overloadCall = isStatic ? `${className}["${operatorString}"](${lhs.getText()}, ${rhs.getText()})` : `${lhs.getText()}["${operatorString}"](${rhs.getText()})`;
249310
249333
  this._logger.debug(`${fileName}: ${expression.getText()} => ${overloadCall}`);
249311
249334
  expression.replaceWithText(overloadCall);
249312
249335
  transformCount++;
@@ -249328,7 +249351,7 @@ var require_OverloadInjector = __commonJS((exports) => {
249328
249351
  const overloadDesc = this._overloadStore.findPrefixUnaryOverload(operatorKind, operandType);
249329
249352
  if (!overloadDesc)
249330
249353
  continue;
249331
- const { className: classNameRaw, classFilePath, operatorString, index } = overloadDesc;
249354
+ const { className: classNameRaw, classFilePath, operatorString } = overloadDesc;
249332
249355
  const classSourceFile = this._project.getSourceFileOrThrow(classFilePath);
249333
249356
  const classDecl = classSourceFile.getClassOrThrow(classNameRaw);
249334
249357
  const classSymbol = classDecl.getSymbol();
@@ -249336,7 +249359,7 @@ var require_OverloadInjector = __commonJS((exports) => {
249336
249359
  throw new Error(`No symbol for class "${classNameRaw}"`);
249337
249360
  const classModuleSpecifier = (0, getModuleSpecifier_1.getModuleSpecifier)(sourceFile, classSourceFile);
249338
249361
  const className = (0, ensureImportedName_1.ensureImportedName)(sourceFile, classSymbol, classModuleSpecifier);
249339
- const overloadCall = `${className}["${operatorString}"][${index}](${operand.getText()})`;
249362
+ const overloadCall = `${className}["${operatorString}"](${operand.getText()})`;
249340
249363
  this._logger.debug(`${fileName}: ${expression.getText()} => ${overloadCall}`);
249341
249364
  expression.replaceWithText(overloadCall);
249342
249365
  transformCount++;
@@ -249358,8 +249381,8 @@ var require_OverloadInjector = __commonJS((exports) => {
249358
249381
  const overloadDesc = this._overloadStore.findPostfixUnaryOverload(operatorKind, operandType);
249359
249382
  if (!overloadDesc)
249360
249383
  continue;
249361
- const { operatorString, index } = overloadDesc;
249362
- const overloadCall = `${operand.getText()}["${operatorString}"][${index}].call(${operand.getText()})`;
249384
+ const { operatorString } = overloadDesc;
249385
+ const overloadCall = `${operand.getText()}["${operatorString}"]()`;
249363
249386
  this._logger.debug(`${fileName}: ${expression.getText()} => ${overloadCall}`);
249364
249387
  expression.replaceWithText(overloadCall);
249365
249388
  transformCount++;
@@ -249387,9 +249410,8 @@ var require_OverloadStore = __commonJS((exports) => {
249387
249410
  var ts_morph_1 = require_ts_morph();
249388
249411
  var operatorSymbols_1 = require_operatorSymbols();
249389
249412
  var ErrorManager_1 = require_ErrorManager();
249390
- var getOperatorStringFromProperty_1 = require_getOperatorStringFromProperty();
249413
+ var getOperatorStringFromMethod_1 = require_getOperatorStringFromMethod();
249391
249414
  var resolveExpressionType_1 = require_resolveExpressionType();
249392
- var unwrapInitializer_1 = require_unwrapInitializer();
249393
249415
  var operatorMap_1 = require_operatorMap();
249394
249416
 
249395
249417
  class OverloadStore extends Map {
@@ -249509,15 +249531,29 @@ var require_OverloadStore = __commonJS((exports) => {
249509
249531
  this._parsedFiles.add(filePath);
249510
249532
  const classes = sourceFile.getClasses();
249511
249533
  classes.forEach((classDecl) => {
249534
+ const className = classDecl.getName();
249535
+ if (!className)
249536
+ return;
249512
249537
  const classType = (0, resolveExpressionType_1.normalizeTypeName)(classDecl.getType().getText());
249513
- classDecl.getProperties().forEach((property) => {
249514
- var _a, _b;
249515
- if (!ts_morph_1.Node.isPropertyDeclaration(property))
249516
- return;
249517
- const isStatic = property.isStatic();
249518
- const operatorString = (0, getOperatorStringFromProperty_1.getOperatorStringFromProperty)(property);
249538
+ const methodGroups = new Map;
249539
+ for (const method of classDecl.getMethods()) {
249540
+ const operatorString = (0, getOperatorStringFromMethod_1.getOperatorStringFromMethod)(method);
249519
249541
  if (!operatorString || !operatorSymbols_1.operatorSymbols.includes(operatorString))
249542
+ continue;
249543
+ let group = methodGroups.get(operatorString);
249544
+ if (!group) {
249545
+ group = [];
249546
+ methodGroups.set(operatorString, group);
249547
+ }
249548
+ const overloadSigs = method.getOverloads();
249549
+ group.push(...overloadSigs.length > 0 ? overloadSigs : [method]);
249550
+ }
249551
+ methodGroups.forEach((methods, operatorString) => {
249552
+ const overloadSigs = methods.filter((m) => !m.hasBody());
249553
+ const sigsToProcess = overloadSigs.length > 0 ? overloadSigs : methods;
249554
+ if (sigsToProcess.length === 0)
249520
249555
  return;
249556
+ const isStatic = sigsToProcess[0].isStatic();
249521
249557
  const binarySyntaxKind = operatorMap_1.operatorMap[operatorString];
249522
249558
  const prefixUnarySyntaxKind = operatorMap_1.prefixUnaryOperatorMap[operatorString];
249523
249559
  const postfixUnarySyntaxKind = operatorMap_1.postfixUnaryOperatorMap[operatorString];
@@ -249526,93 +249562,74 @@ var require_OverloadStore = __commonJS((exports) => {
249526
249562
  const shouldBeStatic = binarySyntaxKind != null && !operatorMap_1.instanceOperators.has(binarySyntaxKind) || prefixUnarySyntaxKind != null;
249527
249563
  const shouldBeInstance = binarySyntaxKind != null && operatorMap_1.instanceOperators.has(binarySyntaxKind) || postfixUnarySyntaxKind != null;
249528
249564
  if (isStatic && !shouldBeStatic || !isStatic && !shouldBeInstance) {
249529
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Expected overload for operator ${operatorString} ` + `to be ${isStatic ? "a static" : "an instance"} field.`, property.getSourceFile().getFilePath(), property.getStartLineNumber(), property.getText().split(`
249530
- `)[0]));
249531
- return;
249532
- }
249533
- const rawInitializer = property.getInitializer();
249534
- if (!rawInitializer) {
249535
- this._addOverloadsFromTypeAnnotation(property, classDecl, classType, filePath, isStatic, operatorString, binarySyntaxKind, prefixUnarySyntaxKind, postfixUnarySyntaxKind);
249565
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Expected overload for operator "${operatorString}" ` + `to be ${isStatic ? "a static" : "an instance"} method.`, sigsToProcess[0].getSourceFile().getFilePath(), sigsToProcess[0].getStartLineNumber(), this._minifyString(sigsToProcess[0].getText().split(`
249566
+ `)[0])));
249536
249567
  return;
249537
249568
  }
249538
- const hasAsConst = ts_morph_1.Node.isAsExpression(rawInitializer) && ((_a = rawInitializer.getTypeNode()) === null || _a === undefined ? undefined : _a.getText()) === "const";
249539
- const initializer3 = (0, unwrapInitializer_1.unwrapInitializer)(rawInitializer);
249540
- if (!initializer3 || !ts_morph_1.Node.isArrayLiteralExpression(initializer3)) {
249541
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload field for operator ${operatorString} ` + "must be an array of overload functions.", property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(property.getName())));
249542
- return;
249543
- }
249544
- if (!hasAsConst) {
249545
- this._errorManager.addError(new ErrorManager_1.ErrorDescription(`Overload array for operator ${operatorString} must use "as const". ` + "Without it, TypeScript widens the array type and loses individual " + "function signatures, causing type errors in generated code.", property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString((_b = property.getText().split(`
249546
- `)[0]) !== null && _b !== undefined ? _b : "")));
249547
- return;
249548
- }
249549
- initializer3.getElements().forEach((element, index) => {
249550
- if (element.isKind(ts_morph_1.SyntaxKind.ArrowFunction) && !isStatic) {
249551
- this._errorManager.addError(new ErrorManager_1.ErrorDescription(`Overload ${index} for operator ${operatorString} must not be an arrow function. ` + "Use a function expression instead, as arrow functions cannot bind `this` correctly for instance operators.", element.getSourceFile().getFilePath(), element.getStartLineNumber(), this._minifyString(element.getText())));
249552
- return;
249553
- }
249554
- if (!element.isKind(ts_morph_1.SyntaxKind.FunctionExpression) && !element.isKind(ts_morph_1.SyntaxKind.FunctionDeclaration) && !element.isKind(ts_morph_1.SyntaxKind.ArrowFunction)) {
249555
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Expected overload ${index} for operator ${operatorString} to be a function.`, element.getSourceFile().getFilePath(), element.getStartLineNumber(), this._minifyString(element.getText())));
249556
- return;
249557
- }
249558
- const funcElement = element;
249559
- const parameters = funcElement.getParameters().filter((p) => p.getName() !== "this");
249569
+ sigsToProcess.forEach((method) => {
249570
+ const parameters = method.getParameters().filter((p) => p.getName() !== "this");
249560
249571
  const paramCount = parameters.length;
249561
249572
  if (paramCount === 2 && isStatic && binarySyntaxKind && !operatorMap_1.instanceOperators.has(binarySyntaxKind)) {
249562
- this._addBinaryOverload(binarySyntaxKind, classDecl, classType, filePath, property, funcElement, parameters, operatorString, index, true);
249573
+ this._addBinaryOverload(binarySyntaxKind, className, classType, filePath, method, parameters, operatorString, true);
249563
249574
  } else if (paramCount === 1 && !isStatic && binarySyntaxKind && operatorMap_1.instanceOperators.has(binarySyntaxKind)) {
249564
- this._addBinaryOverload(binarySyntaxKind, classDecl, classType, filePath, property, funcElement, parameters, operatorString, index, false);
249575
+ this._addBinaryOverload(binarySyntaxKind, className, classType, filePath, method, parameters, operatorString, false);
249565
249576
  } else if (paramCount === 1 && isStatic && prefixUnarySyntaxKind) {
249566
- this._addPrefixUnaryOverload(prefixUnarySyntaxKind, classDecl, classType, filePath, property, funcElement, parameters, operatorString, index);
249577
+ this._addPrefixUnaryOverload(prefixUnarySyntaxKind, className, classType, filePath, method, parameters, operatorString);
249567
249578
  } else if (paramCount === 0 && !isStatic && postfixUnarySyntaxKind) {
249568
- this._addPostfixUnaryOverload(postfixUnarySyntaxKind, classDecl, classType, filePath, property, funcElement, operatorString, index);
249579
+ this._addPostfixUnaryOverload(postfixUnarySyntaxKind, className, classType, filePath, method, operatorString);
249569
249580
  } else {
249570
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload function ${index} for operator ${operatorString} ` + `has invalid parameter count (${paramCount}) for this operator context.`, property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(funcElement.getText())));
249581
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload signature for operator "${operatorString}" ` + `has invalid parameter count (${paramCount}) for this operator context.`, method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249582
+ `)[0])));
249571
249583
  }
249572
249584
  });
249573
249585
  });
249574
249586
  });
249575
249587
  }
249576
- _addBinaryOverload(syntaxKind, classDecl, classType, filePath, property, element, parameters, operatorString, index, isStatic) {
249577
- var _a, _b, _c, _d, _e, _f, _g, _h;
249588
+ _addBinaryOverload(syntaxKind, className, classType, filePath, method, parameters, operatorString, isStatic) {
249589
+ var _a, _b;
249578
249590
  let hasWarning = false;
249579
- const lhsType = isStatic ? (0, resolveExpressionType_1.normalizeTypeName)((_b = (_a = parameters[0]) === null || _a === undefined ? undefined : _a.getType().getText()) !== null && _b !== undefined ? _b : "") : classType;
249580
- const rhsType = isStatic ? (0, resolveExpressionType_1.normalizeTypeName)((_d = (_c = parameters[1]) === null || _c === undefined ? undefined : _c.getType().getText()) !== null && _d !== undefined ? _d : "") : (0, resolveExpressionType_1.normalizeTypeName)((_f = (_e = parameters[0]) === null || _e === undefined ? undefined : _e.getType().getText()) !== null && _f !== undefined ? _f : "");
249591
+ const getParamTypeName = (p) => {
249592
+ var _a2, _b2, _c;
249593
+ return (0, resolveExpressionType_1.normalizeTypeName)((_c = (_b2 = (_a2 = p === null || p === undefined ? undefined : p.getTypeNode()) === null || _a2 === undefined ? undefined : _a2.getText()) !== null && _b2 !== undefined ? _b2 : p === null || p === undefined ? undefined : p.getType().getText()) !== null && _c !== undefined ? _c : "");
249594
+ };
249595
+ const lhsType = isStatic ? getParamTypeName(parameters[0]) : classType;
249596
+ const rhsType = isStatic ? getParamTypeName(parameters[1]) : getParamTypeName(parameters[0]);
249581
249597
  if (isStatic && lhsType !== classType && rhsType !== classType) {
249582
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload for operator ${operatorString} ` + "must have either LHS or RHS parameter matching its class type.", property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(element.getText())));
249598
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload for operator "${operatorString}" ` + "must have either LHS or RHS parameter matching its class type.", method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249599
+ `)[0])));
249583
249600
  hasWarning = true;
249584
249601
  }
249585
- const returnType = element.getReturnType().getText();
249602
+ const returnType = method.getReturnType().getText();
249586
249603
  if (operatorMap_1.comparisonOperators.has(syntaxKind) && returnType !== "boolean") {
249587
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload function ${index} for comparison operator ${operatorString} ` + `must have a return type of 'boolean', got '${returnType}'.`, property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(element.getText())));
249604
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload for comparison operator "${operatorString}" ` + `must have a return type of 'boolean', got '${returnType}'.`, method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249605
+ `)[0])));
249588
249606
  hasWarning = true;
249589
249607
  }
249590
249608
  if (!isStatic && returnType !== "void") {
249591
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload function ${index} for instance operator ${operatorString} ` + `must have a return type of 'void', got '${returnType}'.`, property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(element.getText())));
249609
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload for instance operator "${operatorString}" ` + `must have a return type of 'void', got '${returnType}'.`, method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249610
+ `)[0])));
249592
249611
  hasWarning = true;
249593
249612
  }
249594
- const operatorOverloads = (_g = this.get(syntaxKind)) !== null && _g !== undefined ? _g : new Map;
249595
- const lhsMap = (_h = operatorOverloads.get(lhsType)) !== null && _h !== undefined ? _h : new Map;
249613
+ const operatorOverloads = (_a = this.get(syntaxKind)) !== null && _a !== undefined ? _a : new Map;
249614
+ const lhsMap = (_b = operatorOverloads.get(lhsType)) !== null && _b !== undefined ? _b : new Map;
249596
249615
  if (lhsMap.has(rhsType)) {
249597
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Duplicate overload for operator ${operatorString} with LHS type ${lhsType} and RHS type ${rhsType}`, property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(element.getText())));
249616
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Duplicate overload for operator "${operatorString}" with LHS type ${lhsType} and RHS type ${rhsType}`, method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249617
+ `)[0])));
249598
249618
  hasWarning = true;
249599
249619
  }
249600
249620
  if (hasWarning)
249601
249621
  return;
249602
249622
  lhsMap.set(rhsType, {
249603
249623
  isStatic,
249604
- className: classDecl.getName(),
249624
+ className,
249605
249625
  classFilePath: filePath,
249606
249626
  operatorString,
249607
- index,
249608
249627
  returnType
249609
249628
  });
249610
249629
  operatorOverloads.set(lhsType, lhsMap);
249611
249630
  this.set(syntaxKind, operatorOverloads);
249612
- const funcName = ts_morph_1.Node.isFunctionExpression(element) ? element.getName() : undefined;
249613
249631
  const sl = this._shortTypeName.bind(this);
249614
- const label = funcName ? `${funcName}(${sl(lhsType)}, ${sl(rhsType)})` : `(${sl(lhsType)}, ${sl(rhsType)})`;
249615
- this._logger.debug(`Loaded ${classDecl.getName()}["${operatorString}"][${index}]: ${label} => ${sl(element.getReturnType().getText())}${isStatic ? " (static)" : " (instance)"}`);
249632
+ this._logger.debug(`Loaded ${className}["${operatorString}"]: (${sl(lhsType)}, ${sl(rhsType)}) => ${sl(returnType)}${isStatic ? " (static)" : " (instance)"}`);
249616
249633
  let fileEntries = this._fileEntries.get(filePath);
249617
249634
  if (!fileEntries) {
249618
249635
  fileEntries = [];
@@ -249620,35 +249637,34 @@ var require_OverloadStore = __commonJS((exports) => {
249620
249637
  }
249621
249638
  fileEntries.push({ syntaxKind, lhsType, rhsType });
249622
249639
  }
249623
- _addPrefixUnaryOverload(syntaxKind, classDecl, classType, filePath, property, element, parameters, operatorString, index) {
249624
- var _a, _b, _c;
249640
+ _addPrefixUnaryOverload(syntaxKind, className, classType, filePath, method, parameters, operatorString) {
249641
+ var _a, _b, _c, _d, _e, _f;
249625
249642
  let hasWarning = false;
249626
- const operandType = (0, resolveExpressionType_1.normalizeTypeName)((_b = (_a = parameters[0]) === null || _a === undefined ? undefined : _a.getType().getText()) !== null && _b !== undefined ? _b : "");
249643
+ const operandType = (0, resolveExpressionType_1.normalizeTypeName)((_e = (_c = (_b = (_a = parameters[0]) === null || _a === undefined ? undefined : _a.getTypeNode()) === null || _b === undefined ? undefined : _b.getText()) !== null && _c !== undefined ? _c : (_d = parameters[0]) === null || _d === undefined ? undefined : _d.getType().getText()) !== null && _e !== undefined ? _e : "");
249627
249644
  if (operandType !== classType) {
249628
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Prefix unary overload for operator ${operatorString} ` + "must have its parameter matching its class type.", property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(element.getText())));
249645
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Prefix unary overload for operator "${operatorString}" ` + "must have its parameter matching its class type.", method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249646
+ `)[0])));
249629
249647
  hasWarning = true;
249630
249648
  }
249631
- const operatorOverloads = (_c = this._prefixUnaryOverloads.get(syntaxKind)) !== null && _c !== undefined ? _c : new Map;
249649
+ const operatorOverloads = (_f = this._prefixUnaryOverloads.get(syntaxKind)) !== null && _f !== undefined ? _f : new Map;
249632
249650
  if (operatorOverloads.has(operandType)) {
249633
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Duplicate prefix unary overload for operator ${operatorString} with operand type ${operandType}`, property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(element.getText())));
249651
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Duplicate prefix unary overload for operator "${operatorString}" with operand type ${operandType}`, method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249652
+ `)[0])));
249634
249653
  hasWarning = true;
249635
249654
  }
249636
249655
  if (hasWarning)
249637
249656
  return;
249638
- const returnType = element.getReturnType().getText();
249657
+ const returnType = method.getReturnType().getText();
249639
249658
  operatorOverloads.set(operandType, {
249640
249659
  isStatic: true,
249641
- className: classDecl.getName(),
249660
+ className,
249642
249661
  classFilePath: filePath,
249643
249662
  operatorString,
249644
- index,
249645
249663
  returnType
249646
249664
  });
249647
249665
  this._prefixUnaryOverloads.set(syntaxKind, operatorOverloads);
249648
- const funcName = ts_morph_1.Node.isFunctionExpression(element) ? element.getName() : undefined;
249649
249666
  const sl = this._shortTypeName.bind(this);
249650
- const label = funcName ? `${funcName}(${sl(operandType)})` : `(${sl(operandType)})`;
249651
- this._logger.debug(`Loaded ${classDecl.getName()}["${operatorString}"][${index}]: ${operatorString}${label} => ${sl(returnType)} (prefix unary)`);
249667
+ this._logger.debug(`Loaded ${className}["${operatorString}"]: ${operatorString}(${sl(operandType)}) => ${sl(returnType)} (prefix unary)`);
249652
249668
  let fileEntries = this._prefixUnaryFileEntries.get(filePath);
249653
249669
  if (!fileEntries) {
249654
249670
  fileEntries = [];
@@ -249656,34 +249672,33 @@ var require_OverloadStore = __commonJS((exports) => {
249656
249672
  }
249657
249673
  fileEntries.push({ syntaxKind, operandType });
249658
249674
  }
249659
- _addPostfixUnaryOverload(syntaxKind, classDecl, classType, filePath, property, element, operatorString, index) {
249675
+ _addPostfixUnaryOverload(syntaxKind, className, classType, filePath, method, operatorString) {
249660
249676
  var _a;
249661
249677
  let hasWarning = false;
249662
- const returnType = element.getReturnType().getText();
249678
+ const returnType = method.getReturnType().getText();
249663
249679
  if (returnType !== "void") {
249664
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload function ${index} for postfix operator ${operatorString} ` + `must have a return type of 'void', got '${returnType}'.`, property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(element.getText())));
249680
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload for postfix operator "${operatorString}" ` + `must have a return type of 'void', got '${returnType}'.`, method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249681
+ `)[0])));
249665
249682
  hasWarning = true;
249666
249683
  }
249667
249684
  const operandType = classType;
249668
249685
  const operatorOverloads = (_a = this._postfixUnaryOverloads.get(syntaxKind)) !== null && _a !== undefined ? _a : new Map;
249669
249686
  if (operatorOverloads.has(operandType)) {
249670
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Duplicate postfix unary overload for operator ${operatorString} with operand type ${operandType}`, property.getSourceFile().getFilePath(), property.getStartLineNumber(), this._minifyString(element.getText())));
249687
+ this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Duplicate postfix unary overload for operator "${operatorString}" with operand type ${operandType}`, method.getSourceFile().getFilePath(), method.getStartLineNumber(), this._minifyString(method.getText().split(`
249688
+ `)[0])));
249671
249689
  hasWarning = true;
249672
249690
  }
249673
249691
  if (hasWarning)
249674
249692
  return;
249675
249693
  operatorOverloads.set(operandType, {
249676
249694
  isStatic: false,
249677
- className: classDecl.getName(),
249695
+ className,
249678
249696
  classFilePath: filePath,
249679
249697
  operatorString,
249680
- index,
249681
249698
  returnType
249682
249699
  });
249683
249700
  this._postfixUnaryOverloads.set(syntaxKind, operatorOverloads);
249684
- const funcName = ts_morph_1.Node.isFunctionExpression(element) ? element.getName() : undefined;
249685
- const label = funcName ? `${funcName}()` : "()";
249686
- this._logger.debug(`Loaded ${classDecl.getName()}["${operatorString}"][${index}]: ${this._shortTypeName(operandType)}${operatorString} ${label} (postfix unary)`);
249701
+ this._logger.debug(`Loaded ${className}["${operatorString}"]: ${this._shortTypeName(operandType)}${operatorString} () (postfix unary)`);
249687
249702
  let fileEntries = this._postfixUnaryFileEntries.get(filePath);
249688
249703
  if (!fileEntries) {
249689
249704
  fileEntries = [];
@@ -249691,155 +249706,6 @@ var require_OverloadStore = __commonJS((exports) => {
249691
249706
  }
249692
249707
  fileEntries.push({ syntaxKind, operandType });
249693
249708
  }
249694
- _addOverloadsFromTypeAnnotation(property, classDecl, classType, filePath, isStatic, operatorString, binarySyntaxKind, prefixUnarySyntaxKind, postfixUnarySyntaxKind) {
249695
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
249696
- const propertyType = property.getType();
249697
- if (!propertyType.isTuple())
249698
- return;
249699
- const tupleElements = propertyType.getTupleElements();
249700
- const className = classDecl.getName();
249701
- if (!className)
249702
- return;
249703
- const sl = this._shortTypeName.bind(this);
249704
- for (let index = 0;index < tupleElements.length; index++) {
249705
- const elementType = tupleElements[index];
249706
- const callSigs = elementType.getCallSignatures();
249707
- if (callSigs.length === 0)
249708
- continue;
249709
- const sig = callSigs[0];
249710
- const params = [];
249711
- for (const sym of sig.getParameters()) {
249712
- const name = sym.getName();
249713
- if (name === "this")
249714
- continue;
249715
- const decl = sym.getValueDeclaration();
249716
- if (!decl)
249717
- continue;
249718
- params.push({
249719
- name,
249720
- type: (0, resolveExpressionType_1.normalizeTypeName)(decl.getType().getText())
249721
- });
249722
- }
249723
- const paramCount = params.length;
249724
- const returnType = sig.getReturnType().getText();
249725
- if (paramCount === 2 && isStatic && binarySyntaxKind && !operatorMap_1.instanceOperators.has(binarySyntaxKind)) {
249726
- const lhsType = params[0].type;
249727
- const rhsType = params[1].type;
249728
- if (lhsType !== classType && rhsType !== classType) {
249729
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload for operator ${operatorString} ` + "must have either LHS or RHS parameter matching its class type.", filePath, property.getStartLineNumber(), this._minifyString((_a = property.getText().split(`
249730
- `)[0]) !== null && _a !== undefined ? _a : "")));
249731
- continue;
249732
- }
249733
- if (operatorMap_1.comparisonOperators.has(binarySyntaxKind) && returnType !== "boolean") {
249734
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload function ${index} for comparison operator ${operatorString} ` + `must have a return type of 'boolean', got '${returnType}'.`, filePath, property.getStartLineNumber(), this._minifyString((_b = property.getText().split(`
249735
- `)[0]) !== null && _b !== undefined ? _b : "")));
249736
- continue;
249737
- }
249738
- const operatorOverloads = (_c = this.get(binarySyntaxKind)) !== null && _c !== undefined ? _c : new Map;
249739
- const lhsMap = (_d = operatorOverloads.get(lhsType)) !== null && _d !== undefined ? _d : new Map;
249740
- if (lhsMap.has(rhsType))
249741
- continue;
249742
- lhsMap.set(rhsType, {
249743
- isStatic: true,
249744
- className,
249745
- classFilePath: filePath,
249746
- operatorString,
249747
- index,
249748
- returnType
249749
- });
249750
- operatorOverloads.set(lhsType, lhsMap);
249751
- this.set(binarySyntaxKind, operatorOverloads);
249752
- this._logger.debug(`Loaded ${className}["${operatorString}"][${index}]: (${sl(lhsType)}, ${sl(rhsType)}) => ${sl(returnType)} (static, from .d.ts)`);
249753
- let fileEntries = this._fileEntries.get(filePath);
249754
- if (!fileEntries) {
249755
- fileEntries = [];
249756
- this._fileEntries.set(filePath, fileEntries);
249757
- }
249758
- fileEntries.push({ syntaxKind: binarySyntaxKind, lhsType, rhsType });
249759
- } else if (paramCount === 1 && !isStatic && binarySyntaxKind && operatorMap_1.instanceOperators.has(binarySyntaxKind)) {
249760
- const lhsType = classType;
249761
- const rhsType = params[0].type;
249762
- if (returnType !== "void") {
249763
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload function ${index} for instance operator ${operatorString} ` + `must have a return type of 'void', got '${returnType}'.`, filePath, property.getStartLineNumber(), this._minifyString((_e = property.getText().split(`
249764
- `)[0]) !== null && _e !== undefined ? _e : "")));
249765
- continue;
249766
- }
249767
- const operatorOverloads = (_f = this.get(binarySyntaxKind)) !== null && _f !== undefined ? _f : new Map;
249768
- const lhsMap = (_g = operatorOverloads.get(lhsType)) !== null && _g !== undefined ? _g : new Map;
249769
- if (lhsMap.has(rhsType))
249770
- continue;
249771
- lhsMap.set(rhsType, {
249772
- isStatic: false,
249773
- className,
249774
- classFilePath: filePath,
249775
- operatorString,
249776
- index,
249777
- returnType
249778
- });
249779
- operatorOverloads.set(lhsType, lhsMap);
249780
- this.set(binarySyntaxKind, operatorOverloads);
249781
- this._logger.debug(`Loaded ${className}["${operatorString}"][${index}]: (${sl(lhsType)}, ${sl(rhsType)}) => void (instance, from .d.ts)`);
249782
- let fileEntries = this._fileEntries.get(filePath);
249783
- if (!fileEntries) {
249784
- fileEntries = [];
249785
- this._fileEntries.set(filePath, fileEntries);
249786
- }
249787
- fileEntries.push({ syntaxKind: binarySyntaxKind, lhsType, rhsType });
249788
- } else if (paramCount === 1 && isStatic && prefixUnarySyntaxKind) {
249789
- const operandType = params[0].type;
249790
- if (operandType !== classType) {
249791
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Prefix unary overload for operator ${operatorString} ` + "must have its parameter matching its class type.", filePath, property.getStartLineNumber(), this._minifyString((_h = property.getText().split(`
249792
- `)[0]) !== null && _h !== undefined ? _h : "")));
249793
- continue;
249794
- }
249795
- const operatorOverloads = (_j = this._prefixUnaryOverloads.get(prefixUnarySyntaxKind)) !== null && _j !== undefined ? _j : new Map;
249796
- if (operatorOverloads.has(operandType))
249797
- continue;
249798
- operatorOverloads.set(operandType, {
249799
- isStatic: true,
249800
- className,
249801
- classFilePath: filePath,
249802
- operatorString,
249803
- index,
249804
- returnType
249805
- });
249806
- this._prefixUnaryOverloads.set(prefixUnarySyntaxKind, operatorOverloads);
249807
- this._logger.debug(`Loaded ${className}["${operatorString}"][${index}]: ${operatorString}(${sl(operandType)}) => ${sl(returnType)} (prefix unary, from .d.ts)`);
249808
- let fileEntries = this._prefixUnaryFileEntries.get(filePath);
249809
- if (!fileEntries) {
249810
- fileEntries = [];
249811
- this._prefixUnaryFileEntries.set(filePath, fileEntries);
249812
- }
249813
- fileEntries.push({ syntaxKind: prefixUnarySyntaxKind, operandType });
249814
- } else if (paramCount === 0 && !isStatic && postfixUnarySyntaxKind) {
249815
- if (returnType !== "void") {
249816
- this._errorManager.addWarning(new ErrorManager_1.ErrorDescription(`Overload function ${index} for postfix operator ${operatorString} ` + `must have a return type of 'void', got '${returnType}'.`, filePath, property.getStartLineNumber(), this._minifyString((_k = property.getText().split(`
249817
- `)[0]) !== null && _k !== undefined ? _k : "")));
249818
- continue;
249819
- }
249820
- const operandType = classType;
249821
- const operatorOverloads = (_l = this._postfixUnaryOverloads.get(postfixUnarySyntaxKind)) !== null && _l !== undefined ? _l : new Map;
249822
- if (operatorOverloads.has(operandType))
249823
- continue;
249824
- operatorOverloads.set(operandType, {
249825
- isStatic: false,
249826
- className,
249827
- classFilePath: filePath,
249828
- operatorString,
249829
- index,
249830
- returnType
249831
- });
249832
- this._postfixUnaryOverloads.set(postfixUnarySyntaxKind, operatorOverloads);
249833
- this._logger.debug(`Loaded ${className}["${operatorString}"][${index}]: ${sl(operandType)}${operatorString} () (postfix unary, from .d.ts)`);
249834
- let fileEntries = this._postfixUnaryFileEntries.get(filePath);
249835
- if (!fileEntries) {
249836
- fileEntries = [];
249837
- this._postfixUnaryFileEntries.set(filePath, fileEntries);
249838
- }
249839
- fileEntries.push({ syntaxKind: postfixUnarySyntaxKind, operandType });
249840
- }
249841
- }
249842
- }
249843
249709
  _getTypeChain(typeName) {
249844
249710
  var _a, _b;
249845
249711
  const cached2 = this._typeChainCache.get(typeName);
@@ -250085,7 +249951,7 @@ var require_validateExports = __commonJS((exports) => {
250085
249951
  // ../package/dist/index.js
250086
249952
  var require_dist4 = __commonJS((exports) => {
250087
249953
  Object.defineProperty(exports, "__esModule", { value: true });
250088
- exports.SyntaxKind = exports.Project = exports.Node = exports.operatorSymbols = exports.Operator = exports.validateExports = exports.toV3SourceMap = exports.computeEdits = exports.isPrefixUnaryOperatorSyntaxKind = exports.isPostfixUnaryOperatorSyntaxKind = exports.isOperatorSyntaxKind = exports.OverloadStore = exports.OverloadInjector = exports.unwrapInitializer = exports.resolveExpressionType = exports.getOperatorStringFromProperty = exports.ErrorManager = exports.ErrorDescription = exports.loadConfig = exports.ConsoleLogger = undefined;
249954
+ exports.SyntaxKind = exports.Project = exports.Node = exports.operatorSymbols = exports.Operator = exports.validateExports = exports.toV3SourceMap = exports.computeEdits = exports.isPrefixUnaryOperatorSyntaxKind = exports.isPostfixUnaryOperatorSyntaxKind = exports.isOperatorSyntaxKind = exports.OverloadStore = exports.OverloadInjector = exports.unwrapInitializer = exports.resolveExpressionType = exports.getOperatorStringFromProperty = exports.getOperatorStringFromMethod = exports.ErrorManager = exports.ErrorDescription = exports.loadConfig = exports.ConsoleLogger = undefined;
250089
249955
  var BopConfig_1 = require_BopConfig();
250090
249956
  Object.defineProperty(exports, "ConsoleLogger", { enumerable: true, get: function() {
250091
249957
  return BopConfig_1.ConsoleLogger;
@@ -250100,6 +249966,10 @@ var require_dist4 = __commonJS((exports) => {
250100
249966
  Object.defineProperty(exports, "ErrorManager", { enumerable: true, get: function() {
250101
249967
  return ErrorManager_1.ErrorManager;
250102
249968
  } });
249969
+ var getOperatorStringFromMethod_1 = require_getOperatorStringFromMethod();
249970
+ Object.defineProperty(exports, "getOperatorStringFromMethod", { enumerable: true, get: function() {
249971
+ return getOperatorStringFromMethod_1.getOperatorStringFromMethod;
249972
+ } });
250103
249973
  var getOperatorStringFromProperty_1 = require_getOperatorStringFromProperty();
250104
249974
  Object.defineProperty(exports, "getOperatorStringFromProperty", { enumerable: true, get: function() {
250105
249975
  return getOperatorStringFromProperty_1.getOperatorStringFromProperty;
@@ -263293,58 +263163,48 @@ var postfixUnaryOperatorStrings = new Set(["++", "--"]);
263293
263163
  function generateOverloadProperty(className, operator) {
263294
263164
  if (postfixUnaryOperatorStrings.has(operator)) {
263295
263165
  return [
263296
- ` public readonly "${operator}" = [`,
263297
- ` function (this: ${className}): void {`,
263298
- "\t\t\t// TODO: implement",
263299
- "\t\t},",
263300
- "\t] as const;"
263166
+ ` public "${operator}"(): void {`,
263167
+ "\t\t// TODO: implement",
263168
+ "\t}"
263301
263169
  ].join(`
263302
263170
  `);
263303
263171
  }
263304
263172
  if (exclusivePrefixUnaryStrings.has(operator)) {
263305
263173
  return [
263306
- ` public static readonly "${operator}" = [`,
263307
- ` (a: ${className}): ${className} => {`,
263308
- "\t\t\t// TODO: implement",
263309
- ` return new ${className}();`,
263310
- "\t\t},",
263311
- "\t] as const;"
263174
+ ` public static "${operator}"(a: ${className}): ${className} {`,
263175
+ "\t\t// TODO: implement",
263176
+ ` return new ${className}();`,
263177
+ "\t}"
263312
263178
  ].join(`
263313
263179
  `);
263314
263180
  }
263315
263181
  if (instanceOperatorStrings.has(operator)) {
263316
263182
  return [
263317
- ` public readonly "${operator}" = [`,
263318
- ` function (this: ${className}, other: ${className}): void {`,
263319
- "\t\t\t// TODO: implement",
263320
- "\t\t},",
263321
- "\t] as const;"
263183
+ ` public "${operator}"(other: ${className}): void {`,
263184
+ "\t\t// TODO: implement",
263185
+ "\t}"
263322
263186
  ].join(`
263323
263187
  `);
263324
263188
  }
263325
263189
  if (comparisonOperatorStrings.has(operator)) {
263326
263190
  return [
263327
- ` public static readonly "${operator}" = [`,
263328
- ` (a: ${className}, b: ${className}): boolean => {`,
263329
- "\t\t\t// TODO: implement",
263330
- "\t\t\treturn false;",
263331
- "\t\t},",
263332
- "\t] as const;"
263191
+ ` public static "${operator}"(a: ${className}, b: ${className}): boolean {`,
263192
+ "\t\t// TODO: implement",
263193
+ "\t\treturn false;",
263194
+ "\t}"
263333
263195
  ].join(`
263334
263196
  `);
263335
263197
  }
263336
263198
  return [
263337
- ` public static readonly "${operator}" = [`,
263338
- ` (a: ${className}, b: ${className}): ${className} => {`,
263339
- "\t\t\t// TODO: implement",
263340
- ` return new ${className}();`,
263341
- "\t\t},",
263342
- "\t] as const;"
263199
+ ` public static "${operator}"(a: ${className}, b: ${className}): ${className} {`,
263200
+ "\t\t// TODO: implement",
263201
+ ` return new ${className}();`,
263202
+ "\t}"
263343
263203
  ].join(`
263344
263204
  `);
263345
263205
  }
263346
263206
  server2.registerTool("scaffold_overloads", {
263347
- description: "Generate TypeScript boilerplate for operator overload definitions on a class. " + "Returns code ready to paste into a class body, with correct static/instance " + "placement, as const assertions, and this parameters for instance operators.",
263207
+ description: "Generate TypeScript boilerplate for operator overload definitions on a class. " + "Returns code ready to paste into a class body, with correct static/instance " + "placement and parameter types.",
263348
263208
  inputSchema: {
263349
263209
  className: exports_external.string().describe("The class name to generate overloads for."),
263350
263210
  operators: exports_external.array(exports_external.string()).describe(`Array of operator strings. Valid operators: ${import_boperators2.operatorSymbols.join(", ")}`)
@@ -263384,7 +263244,7 @@ function createCapturingLogger(warnings) {
263384
263244
  };
263385
263245
  }
263386
263246
  server2.registerTool("validate_overloads", {
263387
- description: "Validate operator overload definitions in a single file. " + "Returns structured diagnostics: errors (wrong arity, bad types, missing as const) " + "and warnings (e.g. conflicting overloads). Does not transform the file.",
263247
+ description: "Validate operator overload definitions in a single file. " + "Returns structured diagnostics: errors (wrong arity, bad types) " + "and warnings (e.g. conflicting overloads). Does not transform the file.",
263388
263248
  inputSchema: {
263389
263249
  tsconfig: exports_external.string().describe("Absolute path to tsconfig.json for the project."),
263390
263250
  filePath: exports_external.string().describe("Absolute path to the TypeScript file to validate.")
@@ -263436,75 +263296,83 @@ server2.registerTool("validate_overloads", {
263436
263296
  };
263437
263297
  }
263438
263298
  });
263439
- var instanceCallPattern = /\["([^"]+)"\]\[(\d+)\]\.call\(/;
263440
- var staticCallPattern = /^(\w+)\["([^"]+)"\]\[(\d+)\]\(/;
263299
+ var postfixCallPattern = /\["([^"]+)"\]\(\)$/;
263300
+ var instanceCallPattern = /^([a-z_$]\w*)\["([^"]+)"\]\(/;
263301
+ var staticCallPattern = /^([A-Z]\w*)\["([^"]+)"\]\(/;
263441
263302
  server2.registerTool("explain_expression", {
263442
- description: "Explain a transformed boperators expression. " + 'Given an expression like Vector3["+"][0](a, b) or v["++"][0].call(v), ' + "identifies the operator kind, class, and overload entry. " + "Optionally looks up full overload metadata when tsconfig is provided.",
263303
+ description: "Explain a transformed boperators expression. " + 'Given an expression like Vec2["+"](a, b) or a["+="](b) or a["++"](), ' + "identifies the operator kind, class, and overload entry. " + "Optionally looks up full overload metadata when tsconfig is provided.",
263443
263304
  inputSchema: {
263444
- expression: exports_external.string().describe(`The transformed expression to explain, e.g. 'Vector3["+"][0](a, b)'.`),
263305
+ expression: exports_external.string().describe(`The transformed expression to explain, e.g. 'Vec2["+"](a, b)'.`),
263445
263306
  tsconfig: exports_external.string().optional().describe("Absolute path to tsconfig.json. When provided, the overload is looked up " + "in the project for richer metadata (file path, parameter types).")
263446
263307
  }
263447
263308
  }, async ({ expression, tsconfig }) => {
263448
263309
  try {
263449
263310
  const trimmed = expression.trim();
263311
+ const postfixMatch = trimmed.match(postfixCallPattern);
263312
+ if (postfixMatch) {
263313
+ const [, operator] = postfixMatch;
263314
+ const result = {
263315
+ kind: "postfix unary",
263316
+ operator,
263317
+ isStatic: false,
263318
+ originalExpression: `operand${operator}`,
263319
+ explanation: `Postfix unary operator "${operator}": mutates the operand in place.`
263320
+ };
263321
+ if (tsconfig) {
263322
+ const overloadInfo = lookupOverload(tsconfig, operator, false);
263323
+ if (overloadInfo)
263324
+ Object.assign(result, overloadInfo);
263325
+ }
263326
+ return {
263327
+ content: [
263328
+ { type: "text", text: JSON.stringify(result, null, 2) }
263329
+ ]
263330
+ };
263331
+ }
263450
263332
  const instanceMatch = trimmed.match(instanceCallPattern);
263451
263333
  if (instanceMatch) {
263452
- const [, operator, indexStr] = instanceMatch;
263453
- const index = Number.parseInt(indexStr, 10);
263454
- const callArgs = trimmed.slice(trimmed.indexOf(".call(") + 6, trimmed.lastIndexOf(")"));
263455
- const hasSecondArg = callArgs.includes(",");
263456
- const kind = hasSecondArg ? "instance binary" : "postfix unary";
263457
- const originalPattern = hasSecondArg ? `lhs ${operator} rhs` : `operand${operator}`;
263334
+ const [, , operator] = instanceMatch;
263458
263335
  const result = {
263459
- kind,
263336
+ kind: "instance binary",
263460
263337
  operator,
263461
- index,
263462
263338
  isStatic: false,
263463
- originalExpression: originalPattern,
263464
- explanation: hasSecondArg ? `Instance binary operator "${operator}": mutates the left-hand side in place (e.g. compound assignment).` : `Postfix unary operator "${operator}": mutates the operand in place.`
263339
+ originalExpression: `lhs ${operator} rhs`,
263340
+ explanation: `Instance binary operator "${operator}": mutates the left-hand side in place (e.g. compound assignment).`
263465
263341
  };
263466
263342
  if (tsconfig) {
263467
- const overloadInfo = lookupOverload(tsconfig, operator, index, false);
263343
+ const overloadInfo = lookupOverload(tsconfig, operator, false);
263468
263344
  if (overloadInfo)
263469
263345
  Object.assign(result, overloadInfo);
263470
263346
  }
263471
263347
  return {
263472
263348
  content: [
263473
- {
263474
- type: "text",
263475
- text: JSON.stringify(result, null, 2)
263476
- }
263349
+ { type: "text", text: JSON.stringify(result, null, 2) }
263477
263350
  ]
263478
263351
  };
263479
263352
  }
263480
263353
  const staticMatch = trimmed.match(staticCallPattern);
263481
263354
  if (staticMatch) {
263482
- const [, className, operator, indexStr] = staticMatch;
263483
- const index = Number.parseInt(indexStr, 10);
263355
+ const [, className, operator] = staticMatch;
263484
263356
  const argsStr = trimmed.slice(trimmed.indexOf("](") + 2, trimmed.lastIndexOf(")"));
263485
- const argCount = argsStr.split(",").length;
263357
+ const argCount = argsStr.trim() === "" ? 0 : argsStr.split(",").length;
263486
263358
  const kind = argCount >= 2 ? "static binary" : "prefix unary";
263487
263359
  const originalPattern = argCount >= 2 ? `lhs ${operator} rhs` : `${operator}operand`;
263488
263360
  const result = {
263489
263361
  kind,
263490
263362
  operator,
263491
- index,
263492
263363
  className,
263493
263364
  isStatic: true,
263494
263365
  originalExpression: originalPattern,
263495
263366
  explanation: argCount >= 2 ? `Static binary operator "${operator}": returns a new value from two operands.` : `Prefix unary operator "${operator}": returns a new value from a single operand.`
263496
263367
  };
263497
263368
  if (tsconfig) {
263498
- const overloadInfo = lookupOverload(tsconfig, operator, index, true, className);
263369
+ const overloadInfo = lookupOverload(tsconfig, operator, true, className);
263499
263370
  if (overloadInfo)
263500
263371
  Object.assign(result, overloadInfo);
263501
263372
  }
263502
263373
  return {
263503
263374
  content: [
263504
- {
263505
- type: "text",
263506
- text: JSON.stringify(result, null, 2)
263507
- }
263375
+ { type: "text", text: JSON.stringify(result, null, 2) }
263508
263376
  ]
263509
263377
  };
263510
263378
  }
@@ -263513,8 +263381,9 @@ server2.registerTool("explain_expression", {
263513
263381
  {
263514
263382
  type: "text",
263515
263383
  text: `Could not parse expression as a boperators transformed call. ` + `Expected patterns:
263516
- ` + ` Static: ClassName["op"][index](args)
263517
- ` + ` Instance: expr["op"][index].call(expr, args)`
263384
+ ` + ` Static: ClassName["op"](args)
263385
+ ` + ` Instance: expr["op"](other)
263386
+ ` + ` Postfix: expr["op"]()`
263518
263387
  }
263519
263388
  ],
263520
263389
  isError: true
@@ -263531,15 +263400,13 @@ server2.registerTool("explain_expression", {
263531
263400
  };
263532
263401
  }
263533
263402
  });
263534
- function lookupOverload(tsconfig, operator, index, isStatic, className) {
263403
+ function lookupOverload(tsconfig, operator, isStatic, className) {
263535
263404
  try {
263536
263405
  projectManager.initialize(tsconfig);
263537
263406
  const allOverloads = projectManager.overloadStore.getAllOverloads();
263538
263407
  const match = allOverloads.find((o) => {
263539
263408
  if (o.operatorString !== operator)
263540
263409
  return false;
263541
- if (o.index !== index)
263542
- return false;
263543
263410
  if (className && o.className !== className)
263544
263411
  return false;
263545
263412
  if (o.isStatic !== isStatic)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boperators/mcp-server",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "description": "MCP server for boperators - gives AI assistants access to operator overload information.",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  ],
43
43
  "dependencies": {
44
44
  "@modelcontextprotocol/sdk": "^1.12.1",
45
- "boperators": "0.2.1",
45
+ "boperators": "0.3.0",
46
46
  "zod": "^3.25.0"
47
47
  },
48
48
  "devDependencies": {