-
Notifications
You must be signed in to change notification settings - Fork 83
sem-ver implemented #566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sem-ver implemented #566
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good. Added some comments.
packages/optimizely-sdk/lib/core/custom_attribute_condition_evaluator/index.tests.js
Show resolved
Hide resolved
packages/optimizely-sdk/lib/core/custom_attribute_condition_evaluator/index.tests.js
Show resolved
Hide resolved
const userValueType = typeof userValue; | ||
const conditionValue = condition.value; | ||
|
||
if (conditionValue === null || !isSafeInteger(conditionValue)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of repeating all these checks in every function put it in one function and use it from there see C# for reference. the only evaluation logic should be kept inside every evaluator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistency with previous written evaluators like greaterThanEvaluator, lessThanEvaluator etc will be lost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @mnoman09. If there is repeated logic for checking user inputs for numeric comparison conditions, let's use a shared helper function. If the logic is not exactly the same or it is awkward to share, don't worry about it.
['2.9.9-beta', '2.9.9-beta'], | ||
['2.1', '2.1.0'], | ||
['2', '2.12'], | ||
['2.9', '2.9.1'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add this test where targetSV = 2.1.3 and userver= 2.1.3+build and it should return 0 see this test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2.1.3 > 2.1.3+build
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No this is a corner case that we covered in all other sdks. you can see java link I shared above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
const userValueType = typeof userValue; | ||
const conditionValue = condition.value; | ||
|
||
if (conditionValue === null || !isSafeInteger(conditionValue)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @mnoman09. If there is repeated logic for checking user inputs for numeric comparison conditions, let's use a shared helper function. If the logic is not exactly the same or it is awkward to share, don't worry about it.
export const VERSION_TYPE = { | ||
IS_PRE_RELEASE: '-', | ||
IS_BUILD: '+' | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeScript has enum
and const enum
declarations. Some can be compiled into constant values leading to smaller code size. Please check the documentation for enums. Let's not use an object with long property names unless necessary, to avoid bloating the code.
|
||
} | ||
|
||
export function compareVersion(conditionsVersion: string, userProvidedVersion: string): number | null { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a documentation comment
if (!userVersionParts || !conditionsVersionParts) | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style preference is to always use brackets with if statements.
if (userVersionPartsLen <= idx) | ||
return isPreReleaseInconditionsVersion || isBuildInconditionsVersion ? 1 : -1 | ||
else if (!isNumber(userVersionParts[idx])) { | ||
if (userVersionParts[idx] < conditionsVersionParts[idx]) { | ||
return isPreReleaseInconditionsVersion && !isPreReleaseInuserProvidedVersion ? 1 : -1; | ||
} | ||
else if (userVersionParts[idx] > conditionsVersionParts[idx]) { | ||
return !isPreReleaseInconditionsVersion && isPreReleaseInuserProvidedVersion ? -1 : 1; | ||
} | ||
} | ||
else { | ||
const userVersionPart = parseInt(userVersionParts[idx]) | ||
const conditionsVersionPart = parseInt(conditionsVersionParts[idx]) | ||
if (userVersionPart > conditionsVersionPart) | ||
return 1; | ||
else if (userVersionPart < conditionsVersionPart) | ||
return -1; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please try to simplify the control flow, there are a lot of nested conditionals.
* | ||
*/ | ||
function isNumber(content: string): boolean { | ||
return content.match(/^[0-9]+$/) != null ? true : false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this equivalent?
return content.match(/^[0-9]+$/) != null ? true : false; | |
return /^\d+$/.test(content); |
(see: Regular Expression docs for JS)
Also: I suggest declaring regular expression once higher up in module scope, then reference here (DIGIT_STRING_REGEXP.test(content)
).
* | ||
*/ | ||
function hasWhiteSpaces(version: string): boolean { | ||
return version.includes(' '); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about other space characters (tab, newline, etc.)? Should we use space regexp character class?
return version.includes(' '); | |
return /\s/.test(version); |
- Minor concern:
String.prototype.includes
is not supported in very old JS environments. - Is there any performance difference between
String.prototype.includes
and regular expressiontest
method?
//check for pre release e.g. 1.0.0-alpha where 'alpha' is a pre release | ||
//otherwise check for build e.g. 1.0.0+001 where 001 is a build metadata | ||
if (isPreReleaseVersion(version)) { | ||
targetPrefix = version.substring(0, version.indexOf(VERSION_TYPE.IS_PRE_RELEASE)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IS_PRE_RELEASE
sounds like a boolean. I prefer PRE_RELEASE_VERSION_DELIMITER
.
targetSuffix = version.substring(version.indexOf(VERSION_TYPE.IS_PRE_RELEASE) + 1); | ||
} | ||
else if (isBuildVersion(version)) { | ||
targetPrefix = version.substring(0, version.indexOf(VERSION_TYPE.IS_BUILD)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BUILD_VERSION_DELIMITER
* @return {boolean} The array of version split into smaller parts i.e major, minor, patch etc | ||
* null if given version is in invalid format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would consumer code be clearer if we had an interface for semantic version components?
interface SemanticVersionComponents {
major: number;
minor: number;
patch: number;
preRelease?: number
build?: number
}
Then:
function splitVersion(version: string): SemanticVersionComponents | null {
Summary
Test plan