backtest-kit 2.0.4 → 2.0.5
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.
- package/build/index.cjs +101 -2
- package/build/index.mjs +101 -2
- package/package.json +1 -1
package/build/index.cjs
CHANGED
|
@@ -9918,6 +9918,83 @@ const VALID_METHOD_NAMES = [
|
|
|
9918
9918
|
"riskRejection",
|
|
9919
9919
|
"dispose",
|
|
9920
9920
|
];
|
|
9921
|
+
/**
|
|
9922
|
+
* Calculates the Levenshtein distance between two strings.
|
|
9923
|
+
*
|
|
9924
|
+
* Levenshtein distance is the minimum number of single-character edits
|
|
9925
|
+
* (insertions, deletions, or substitutions) required to change one string into another.
|
|
9926
|
+
* Used to find typos and similar method names in validation.
|
|
9927
|
+
*
|
|
9928
|
+
* @param str1 - First string to compare
|
|
9929
|
+
* @param str2 - Second string to compare
|
|
9930
|
+
* @returns Number of edits needed to transform str1 into str2
|
|
9931
|
+
*/
|
|
9932
|
+
const LEVENSHTEIN_DISTANCE = (str1, str2) => {
|
|
9933
|
+
const len1 = str1.length;
|
|
9934
|
+
const len2 = str2.length;
|
|
9935
|
+
// Create a 2D array for dynamic programming
|
|
9936
|
+
const matrix = Array.from({ length: len1 + 1 }, () => Array(len2 + 1).fill(0));
|
|
9937
|
+
// Initialize first column and row
|
|
9938
|
+
for (let i = 0; i <= len1; i++) {
|
|
9939
|
+
matrix[i][0] = i;
|
|
9940
|
+
}
|
|
9941
|
+
for (let j = 0; j <= len2; j++) {
|
|
9942
|
+
matrix[0][j] = j;
|
|
9943
|
+
}
|
|
9944
|
+
// Fill the matrix
|
|
9945
|
+
for (let i = 1; i <= len1; i++) {
|
|
9946
|
+
for (let j = 1; j <= len2; j++) {
|
|
9947
|
+
const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
9948
|
+
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, // deletion
|
|
9949
|
+
matrix[i][j - 1] + 1, // insertion
|
|
9950
|
+
matrix[i - 1][j - 1] + cost // substitution
|
|
9951
|
+
);
|
|
9952
|
+
}
|
|
9953
|
+
}
|
|
9954
|
+
return matrix[len1][len2];
|
|
9955
|
+
};
|
|
9956
|
+
/**
|
|
9957
|
+
* Finds suggestions for a method name based on similarity scoring.
|
|
9958
|
+
*
|
|
9959
|
+
* Uses Levenshtein distance and partial string matching to find similar method names.
|
|
9960
|
+
* Returns suggestions sorted by similarity (most similar first).
|
|
9961
|
+
* Used to provide helpful "Did you mean?" suggestions in validation error messages.
|
|
9962
|
+
*
|
|
9963
|
+
* @param methodName - The invalid method name to find suggestions for
|
|
9964
|
+
* @param validNames - List of valid method names to search through
|
|
9965
|
+
* @param maxDistance - Maximum Levenshtein distance to consider (default: 3)
|
|
9966
|
+
* @returns Array of suggested method names sorted by similarity
|
|
9967
|
+
*/
|
|
9968
|
+
const FIND_SUGGESTIONS = (methodName, validNames, maxDistance = 3) => {
|
|
9969
|
+
const lowerMethodName = methodName.toLowerCase();
|
|
9970
|
+
// Calculate similarity score for each valid name
|
|
9971
|
+
const suggestions = validNames
|
|
9972
|
+
.map((validName) => {
|
|
9973
|
+
const lowerValidName = validName.toLowerCase();
|
|
9974
|
+
const distance = LEVENSHTEIN_DISTANCE(lowerMethodName, lowerValidName);
|
|
9975
|
+
// Check for partial matches
|
|
9976
|
+
const hasPartialMatch = lowerValidName.includes(lowerMethodName) ||
|
|
9977
|
+
lowerMethodName.includes(lowerValidName);
|
|
9978
|
+
return {
|
|
9979
|
+
name: validName,
|
|
9980
|
+
distance,
|
|
9981
|
+
hasPartialMatch,
|
|
9982
|
+
};
|
|
9983
|
+
})
|
|
9984
|
+
.filter((item) => item.distance <= maxDistance || item.hasPartialMatch)
|
|
9985
|
+
.sort((a, b) => {
|
|
9986
|
+
// Prioritize partial matches
|
|
9987
|
+
if (a.hasPartialMatch && !b.hasPartialMatch)
|
|
9988
|
+
return -1;
|
|
9989
|
+
if (!a.hasPartialMatch && b.hasPartialMatch)
|
|
9990
|
+
return 1;
|
|
9991
|
+
// Then sort by distance
|
|
9992
|
+
return a.distance - b.distance;
|
|
9993
|
+
})
|
|
9994
|
+
.slice(0, 3) // Limit to top 3 suggestions
|
|
9995
|
+
.map((item) => item.name);
|
|
9996
|
+
return suggestions;
|
|
9997
|
+
};
|
|
9921
9998
|
/**
|
|
9922
9999
|
* Validates that all public methods in a class-based action handler are in the allowed list.
|
|
9923
10000
|
*
|
|
@@ -9944,7 +10021,18 @@ const VALIDATE_CLASS_METHODS = (actionName, handler, self) => {
|
|
|
9944
10021
|
const descriptor = Object.getOwnPropertyDescriptor(handler.prototype, methodName);
|
|
9945
10022
|
const isMethod = descriptor && typeof descriptor.value === "function";
|
|
9946
10023
|
if (isMethod && !VALID_METHOD_NAMES.includes(methodName)) {
|
|
9947
|
-
const
|
|
10024
|
+
const suggestions = FIND_SUGGESTIONS(methodName, VALID_METHOD_NAMES);
|
|
10025
|
+
const lines = [
|
|
10026
|
+
`ActionSchema ${actionName} contains invalid method "${methodName}". `,
|
|
10027
|
+
`Valid methods are: ${VALID_METHOD_NAMES.join(", ")}`,
|
|
10028
|
+
];
|
|
10029
|
+
if (suggestions.length > 0) {
|
|
10030
|
+
lines.push("");
|
|
10031
|
+
lines.push(`Do you mean: ${suggestions.join(", ")}?`);
|
|
10032
|
+
lines.push("");
|
|
10033
|
+
}
|
|
10034
|
+
lines.push(`If you want to keep this property name use one of these patterns: _${methodName} or #${methodName}`);
|
|
10035
|
+
const msg = functoolsKit.str.newline(lines);
|
|
9948
10036
|
self.loggerService.log(`actionValidationService exception thrown`, {
|
|
9949
10037
|
msg,
|
|
9950
10038
|
});
|
|
@@ -9973,7 +10061,18 @@ const VALIDATE_OBJECT_METHODS = (actionName, handler, self) => {
|
|
|
9973
10061
|
}
|
|
9974
10062
|
if (typeof handler[methodName] === "function" &&
|
|
9975
10063
|
!VALID_METHOD_NAMES.includes(methodName)) {
|
|
9976
|
-
const
|
|
10064
|
+
const suggestions = FIND_SUGGESTIONS(methodName, VALID_METHOD_NAMES);
|
|
10065
|
+
const lines = [
|
|
10066
|
+
`ActionSchema ${actionName} contains invalid method "${methodName}". `,
|
|
10067
|
+
`Valid methods are: ${VALID_METHOD_NAMES.join(", ")}`,
|
|
10068
|
+
];
|
|
10069
|
+
if (suggestions.length > 0) {
|
|
10070
|
+
lines.push("");
|
|
10071
|
+
lines.push(`Do you mean: ${suggestions.join(", ")}?`);
|
|
10072
|
+
lines.push("");
|
|
10073
|
+
}
|
|
10074
|
+
lines.push(`If you want to keep this property name use one of these patterns: _${methodName} or #${methodName}`);
|
|
10075
|
+
const msg = functoolsKit.str.newline(lines);
|
|
9977
10076
|
self.loggerService.log(`actionValidationService exception thrown`, {
|
|
9978
10077
|
msg,
|
|
9979
10078
|
});
|
package/build/index.mjs
CHANGED
|
@@ -9898,6 +9898,83 @@ const VALID_METHOD_NAMES = [
|
|
|
9898
9898
|
"riskRejection",
|
|
9899
9899
|
"dispose",
|
|
9900
9900
|
];
|
|
9901
|
+
/**
|
|
9902
|
+
* Calculates the Levenshtein distance between two strings.
|
|
9903
|
+
*
|
|
9904
|
+
* Levenshtein distance is the minimum number of single-character edits
|
|
9905
|
+
* (insertions, deletions, or substitutions) required to change one string into another.
|
|
9906
|
+
* Used to find typos and similar method names in validation.
|
|
9907
|
+
*
|
|
9908
|
+
* @param str1 - First string to compare
|
|
9909
|
+
* @param str2 - Second string to compare
|
|
9910
|
+
* @returns Number of edits needed to transform str1 into str2
|
|
9911
|
+
*/
|
|
9912
|
+
const LEVENSHTEIN_DISTANCE = (str1, str2) => {
|
|
9913
|
+
const len1 = str1.length;
|
|
9914
|
+
const len2 = str2.length;
|
|
9915
|
+
// Create a 2D array for dynamic programming
|
|
9916
|
+
const matrix = Array.from({ length: len1 + 1 }, () => Array(len2 + 1).fill(0));
|
|
9917
|
+
// Initialize first column and row
|
|
9918
|
+
for (let i = 0; i <= len1; i++) {
|
|
9919
|
+
matrix[i][0] = i;
|
|
9920
|
+
}
|
|
9921
|
+
for (let j = 0; j <= len2; j++) {
|
|
9922
|
+
matrix[0][j] = j;
|
|
9923
|
+
}
|
|
9924
|
+
// Fill the matrix
|
|
9925
|
+
for (let i = 1; i <= len1; i++) {
|
|
9926
|
+
for (let j = 1; j <= len2; j++) {
|
|
9927
|
+
const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
9928
|
+
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, // deletion
|
|
9929
|
+
matrix[i][j - 1] + 1, // insertion
|
|
9930
|
+
matrix[i - 1][j - 1] + cost // substitution
|
|
9931
|
+
);
|
|
9932
|
+
}
|
|
9933
|
+
}
|
|
9934
|
+
return matrix[len1][len2];
|
|
9935
|
+
};
|
|
9936
|
+
/**
|
|
9937
|
+
* Finds suggestions for a method name based on similarity scoring.
|
|
9938
|
+
*
|
|
9939
|
+
* Uses Levenshtein distance and partial string matching to find similar method names.
|
|
9940
|
+
* Returns suggestions sorted by similarity (most similar first).
|
|
9941
|
+
* Used to provide helpful "Did you mean?" suggestions in validation error messages.
|
|
9942
|
+
*
|
|
9943
|
+
* @param methodName - The invalid method name to find suggestions for
|
|
9944
|
+
* @param validNames - List of valid method names to search through
|
|
9945
|
+
* @param maxDistance - Maximum Levenshtein distance to consider (default: 3)
|
|
9946
|
+
* @returns Array of suggested method names sorted by similarity
|
|
9947
|
+
*/
|
|
9948
|
+
const FIND_SUGGESTIONS = (methodName, validNames, maxDistance = 3) => {
|
|
9949
|
+
const lowerMethodName = methodName.toLowerCase();
|
|
9950
|
+
// Calculate similarity score for each valid name
|
|
9951
|
+
const suggestions = validNames
|
|
9952
|
+
.map((validName) => {
|
|
9953
|
+
const lowerValidName = validName.toLowerCase();
|
|
9954
|
+
const distance = LEVENSHTEIN_DISTANCE(lowerMethodName, lowerValidName);
|
|
9955
|
+
// Check for partial matches
|
|
9956
|
+
const hasPartialMatch = lowerValidName.includes(lowerMethodName) ||
|
|
9957
|
+
lowerMethodName.includes(lowerValidName);
|
|
9958
|
+
return {
|
|
9959
|
+
name: validName,
|
|
9960
|
+
distance,
|
|
9961
|
+
hasPartialMatch,
|
|
9962
|
+
};
|
|
9963
|
+
})
|
|
9964
|
+
.filter((item) => item.distance <= maxDistance || item.hasPartialMatch)
|
|
9965
|
+
.sort((a, b) => {
|
|
9966
|
+
// Prioritize partial matches
|
|
9967
|
+
if (a.hasPartialMatch && !b.hasPartialMatch)
|
|
9968
|
+
return -1;
|
|
9969
|
+
if (!a.hasPartialMatch && b.hasPartialMatch)
|
|
9970
|
+
return 1;
|
|
9971
|
+
// Then sort by distance
|
|
9972
|
+
return a.distance - b.distance;
|
|
9973
|
+
})
|
|
9974
|
+
.slice(0, 3) // Limit to top 3 suggestions
|
|
9975
|
+
.map((item) => item.name);
|
|
9976
|
+
return suggestions;
|
|
9977
|
+
};
|
|
9901
9978
|
/**
|
|
9902
9979
|
* Validates that all public methods in a class-based action handler are in the allowed list.
|
|
9903
9980
|
*
|
|
@@ -9924,7 +10001,18 @@ const VALIDATE_CLASS_METHODS = (actionName, handler, self) => {
|
|
|
9924
10001
|
const descriptor = Object.getOwnPropertyDescriptor(handler.prototype, methodName);
|
|
9925
10002
|
const isMethod = descriptor && typeof descriptor.value === "function";
|
|
9926
10003
|
if (isMethod && !VALID_METHOD_NAMES.includes(methodName)) {
|
|
9927
|
-
const
|
|
10004
|
+
const suggestions = FIND_SUGGESTIONS(methodName, VALID_METHOD_NAMES);
|
|
10005
|
+
const lines = [
|
|
10006
|
+
`ActionSchema ${actionName} contains invalid method "${methodName}". `,
|
|
10007
|
+
`Valid methods are: ${VALID_METHOD_NAMES.join(", ")}`,
|
|
10008
|
+
];
|
|
10009
|
+
if (suggestions.length > 0) {
|
|
10010
|
+
lines.push("");
|
|
10011
|
+
lines.push(`Do you mean: ${suggestions.join(", ")}?`);
|
|
10012
|
+
lines.push("");
|
|
10013
|
+
}
|
|
10014
|
+
lines.push(`If you want to keep this property name use one of these patterns: _${methodName} or #${methodName}`);
|
|
10015
|
+
const msg = str.newline(lines);
|
|
9928
10016
|
self.loggerService.log(`actionValidationService exception thrown`, {
|
|
9929
10017
|
msg,
|
|
9930
10018
|
});
|
|
@@ -9953,7 +10041,18 @@ const VALIDATE_OBJECT_METHODS = (actionName, handler, self) => {
|
|
|
9953
10041
|
}
|
|
9954
10042
|
if (typeof handler[methodName] === "function" &&
|
|
9955
10043
|
!VALID_METHOD_NAMES.includes(methodName)) {
|
|
9956
|
-
const
|
|
10044
|
+
const suggestions = FIND_SUGGESTIONS(methodName, VALID_METHOD_NAMES);
|
|
10045
|
+
const lines = [
|
|
10046
|
+
`ActionSchema ${actionName} contains invalid method "${methodName}". `,
|
|
10047
|
+
`Valid methods are: ${VALID_METHOD_NAMES.join(", ")}`,
|
|
10048
|
+
];
|
|
10049
|
+
if (suggestions.length > 0) {
|
|
10050
|
+
lines.push("");
|
|
10051
|
+
lines.push(`Do you mean: ${suggestions.join(", ")}?`);
|
|
10052
|
+
lines.push("");
|
|
10053
|
+
}
|
|
10054
|
+
lines.push(`If you want to keep this property name use one of these patterns: _${methodName} or #${methodName}`);
|
|
10055
|
+
const msg = str.newline(lines);
|
|
9957
10056
|
self.loggerService.log(`actionValidationService exception thrown`, {
|
|
9958
10057
|
msg,
|
|
9959
10058
|
});
|