Files
MQL5Data/Documents/JsModules/x-value.tools.js
T
saherelm f7040490c8 apply some changes to Pack npm scripts for support Pack and Compile Workspace ...
add XCHVWAP Indicator, extends it's Helper class and implement it's usage inside XCH strategy ...
2024-08-03 06:14:47 +03:30

1528 lines
32 KiB
JavaScript

/**
* Value Tools Module ...
* a module for Validate args and values ...
*
* Maintainer
*
* Hadi Khazaee Asl <https://saherelm.ir> (hadi_khazaee_asl@yahoo.com)
*/
//
//#region Imports ...
const XTypeTools = require('./x-type-detector.tools');
//#endregion
//
//#region Actions ...
/**
* validate a value as an argument ...
*
* @param {string} value the value which going to validate ...
* @returns
*/
function isValidArg(value) {
//
let result = false;
//
result = value &&
value.length > 0;
//
return result;
}
/**
* validate a collection of valuea as an arguments ...
*
* @param {string|string[]} values the value collection which going to checked ...
* @returns
*/
function isValidArgs(values) {
//
// Normalize Values ...
const normalValues = toNormalArray(values);
if (!hasChildArray(normalValues)) {
return false;
}
//
let result = normalValues.every(nv => isValidArg(nv));
return result;
}
/**
* converts content to an array object ...
*
* @param {string|string[]} content the content which required to normalized ...
* @returns {string[]} array object ...
*/
function toNormalArray(content = '') {
//
// Validate Args ...
if (!isValidArg(content)) {
return [];
}
//
const result = Array.isArray(content) ?
[...content] :
content.includes(',') &&
content !== ',' ?
[...content.split(',')] :
[content];
//
return result;
}
/**
* determines value is array and has atleast one child ...
*
* @param {any} value the value which going to checked ...
* @returns {boolean} result of checking ...
*/
function hasChildArray(value) {
//
let result = false;
result = value &&
Array.isArray(value) &&
value.length > 0;
//
return result;
}
/**
* check an string is ends with specified symbol ...
*
* @param {string} symbol specified search symbol ...
* @param {string} value specified search content ...
* @param {boolean} ignoreCase specified search case sensitive or not ...
* @returns
*/
function endsWidth(
symbol = '',
value = '',
ignoreCase = true
) {
//
if (!isValidArg(value)) {
return false;
}
//
if (!isValidArg(symbol)) {
return true;
}
//
// TODO: uncomment it if necessary ...
// symbol = symbol.trim();
//
let result = false;
const subtractedContent = value.substring(value.length - symbol.length);
result = !!ignoreCase ?
subtractedContent
.toLowerCase() === symbol
.toLowerCase() :
subtractedContent === symbol;
//
return result;
}
/**
* surround specified content by provided symbol ...
*
* @param {string} symbol surround string ...
* @param {string} content used content to surrounded by symbol ...
* @returns surrounded content ...
*/
function surroundBy(
symbol = '',
content = ''
) {
//
// Validate Args ...
if (!isValidArg(content)) {
content = '';
}
//
if (!isValidArg(symbol)) {
symbol = '';
}
//
if (isSurrounded(symbol, content)) {
return content;
}
//
const result = `${symbol}${content}${symbol}`;
return result;
}
/**
* convert a parsed sign to clear string ...
*
* @param {string} value a parsed content ...
* @returns clear parsed signs ...
*/
function toStringExpression(value) {
//
let result = '';
result = value;
//
if (
!value ||
!isValidArg(value) ||
!isSurroundedString(value)
) {
return result;
}
//
const startSymbol = value.charAt(0);
const endSymbol = value.charAt(value.length - 1);
//
if (startSymbol !== endSymbol) {
return result;
}
//
if (
startSymbol === "\"" ||
startSymbol === "\'"
) {
result = clearSurround(startSymbol, value);
}
//
return result;
}
/**
* find and cleare proposed candidates from specified content ...
*
* @param {string|string[]} candidates the proposed string(s) whic going to cleared from content ...
* @param {string} content the destination content which used to find and replace candidates on it ...
* @returns cleared content ...
*/
function clearContent(
candidates,
content
) {
//
// Validate Args ...
if (
!candidates ||
!isValidArg(content)
) {
return '';
}
//
// Normalize candidates ...
const normalCandidates = toNormalArray(candidates)
.filter(c => isValidArg(c));
if (!hasChildArray(normalCandidates)) {
return content;
}
//
// define regexp for content ...
const regExpExpression = normalCandidates.join('|');
const regExp = new RegExp(
regExpExpression,
'gi'
);
//
let result = '';
result = content.replace(regExp, '');
//
return result;
}
/**
* clear surrounded symbol from content ...
*
* @param {string} symbol specified search symbol ...
* @param {string} content specified content to clear ...
* @returns
*/
function clearSurround(
symbol = '',
content = ''
) {
//
// Validate Args ...
if (
!isValidArg(content) ||
(isValidArg(symbol) &&
symbol.length >= content.length - 1)
) {
return '';
}
//
// Validate Surround ...
if (!isSurrounded(symbol, content)) {
return content;
}
//
if (!isValidArg(symbol)) {
return content;
}
//
let result = content.substring(symbol.length, content.length - symbol.length);
return result;
}
/**
* clear object sign ...
*
* @param {string} content
* @returns cleared content ...
*/
function clearObjectSurround(content = '') {
//
// Validate Args ...
if (
!isValidArg(content) ||
!isSurroundedObject(content)
) {
return content;
}
//
const endIndex = content.length - (
endsWidth('}', content) ?
1 :
endsWidth('},', content) ||
endsWidth('};', content) ||
endsWidth('}\n', content) ?
2 :
0
);
//
const result = content.substring(1, endIndex);
return result;
}
/**
* clear array sign ...
*
* @param {string} content
* @returns cleared content ...
*/
function clearArraySurround(content = '') {
//
// Validate Args ...
if (
!isValidArg(content) ||
!isSurroundedArray(content)
) {
return content;
}
//
const endIndex = content.length - (
endsWidth(']', content) ?
1 :
endsWidth('],', content) ||
endsWidth('];', content) ||
endsWidth(']\n', content) ?
2 :
0
);
//
const result = content.substring(1, endIndex);
return result;
}
/**
* slice a content to individual parts ...
*
* @param {number|number[]} indexes which indexes used to slice ...
* @param {strng} content the content which going to sliced ...
* @returns sliced parts of content ...
*/
function sliceContent(indexes, content) {
//
// Validate Args ...
if (
!isValidArg(indexes) ||
!isValidArg(content)
) {
return [];
}
//
// Normalize indexes ...
const normalIndexes = toNormalArray(indexes)
.filter(index => index > -1 && index < content.length);
if (!hasChildArray(normalIndexes)) {
return [];
}
//
let result = [''];
result.pop();
//
let lastIndex = 0;
for (const index of normalIndexes) {
//
const part = content.substring(lastIndex, index);
if (isValidArg(part)) {
result.push(part.trim());
}
//
lastIndex = index + 1;
}
//
// check remained parts ...
if (lastIndex < content.length) {
//
const part = content.substring(lastIndex);
if (isValidArg(part)) {
result.push(part.trim());
}
}
//
return result;
}
/**
* check an string is starts and ends with specified symbol ...
*
* @param {string} symbol specified search symbol ...
* @param {string} content specified search content ...
* @param {boolean} ignoreCase specified search case sensitive or not ...
* @returns
*/
function isSurrounded(
symbol = '',
content = '',
ignoreCase = true
) {
//
// Validate Args ...
if (!isValidArg(content)) {
return false;
}
//
if (!isValidArg(symbol)) {
return true;
}
//
symbol = symbol.trim();
//
let result = false;
result = (!!ignoreCase ?
content
.toLowerCase()
.startsWith(symbol.toLowerCase()) :
content.startsWith(symbol)
) &&
endsWidth(symbol, content, ignoreCase);
//
return result;
}
/**
* determines a content is an string surrounded value or not ...
*
* @param {string} content a content which going to check ...
* @returns
*/
function isSurroundedString(content = '') {
//
// Validate Args ...
if (!isValidArg(content)) {
return false;
}
//
let result = false;
result = (
content.startsWith('\'') &&
(
endsWidth('\'', content) ||
endsWidth('\',', content) ||
endsWidth('\';', content) ||
endsWidth('\'\n', content)
) ||
content.startsWith('\"') &&
(
endsWidth('\"', content) ||
endsWidth('\",', content) ||
endsWidth('\";', content) ||
endsWidth('\"\n', content)
) ||
content.startsWith('`') &&
(
endsWidth('\`', content) ||
endsWidth('\`,', content) ||
endsWidth('\`;', content) ||
endsWidth('\`\n', content)
)
);
return result;
}
/**
* check a content is an array content or not ...
*
* @param {string} content
* @returns
*/
function isSurroundedArray(content = '') {
//
// Validate Args ...
if (!isValidArg(content)) {
return false;
}
//
let result = false;
result = content.startsWith('[') &&
(
endsWidth(']', content) ||
endsWidth('],', content) ||
endsWidth('];', content) ||
endsWidth(']\n', content)
);
return result;
}
/**
* check a content is an object content or not ...
*
* @param {string} content
* @returns
*/
function isSurroundedObject(content = '') {
//
// Validate Args ...
if (!isValidArg(content)) {
return false;
}
//
let result = false;
result = content.startsWith('{') &&
(
endsWidth('}', content) ||
endsWidth('},', content) ||
endsWidth('};', content) ||
endsWidth('}\n', content)
);
return result;
}
/**
* check an index model is contains inside anothers or not ...
*
* @param {{ start: number, end: number}} source the source index model to check ...
* @param {...{ start: number, end: number}} dest the collection of index models which going to check ...
* @returns
*/
function isIndexInside(source, ...dest) {
//
let result = false;
//
// Validate Args ...
if (!source || !dest) {
return result;
}
//
// Check idx is standard ...
if (
!source ||
!source.end ||
!source.start ||
source.start > source.end
) {
return false;
}
//
// Check types of destinations ...
for (let index of dest) {
//
// Check idx is standard ...
if (
!index ||
!index.end ||
!index.start ||
index.start > index.end
) {
return false;
}
}
//
if (dest.includes(source)) {
dest = dest.filter(d => d !== source);
}
//
const insideContentIndex = dest.find(dIndex => {
//
const result = source.start >= dIndex.start &&
source.start <= dIndex.end &&
source.end >= dIndex.start &&
source.end <= dIndex.end;
return result;
});
//
result = insideContentIndex;
return result;
}
/**
* check a number exists in
* @param {number} idx the number which going to check ...
* @param {{ start: number, end: number}} index the index model
* @returns
*/
function isInsideIndex(idx = -1, index) {
//
let result = false;
//
// Validate Args ...
if (
!index ||
!index.hasOwnProperty('end') ||
!index.hasOwnProperty('start')
) {
return result;
}
//
result = idx > index.start && idx < index.end;
return result;
}
/**
* determines an object is key/value and type ...
*
* @param {any} content the object which we are going to check ...
* @returns
*/
function isKeyValueType(content) {
//
const result = content &&
content.hasOwnProperty('key') &&
content.hasOwnProperty('type') &&
content.hasOwnProperty('value');
//
return result;
}
/**
* find all indexes of token(s) in content ...
*
* @param {string|string[]} tokens the tokens which require to search ...
* @param {string} content the content which using to search ...
* @returns {number[]} all occured indexes ...
*/
function findAllIndexes(
tokens,
content
) {
//
// Validate Args ...
if (
!isValidArg(tokens) ||
!isValidArg(content)
) {
return [];
}
//
// normalize tokens ...
const normalTokens = toNormalArray(tokens);
if (!hasChildArray(normalTokens)) {
return [];
}
//
// Parse contents ...
let match;
const result = [];
const regExp = new RegExp(
normalTokens.join('|'),
'g'
);
while ((match = regExp.exec(content)) !== null) {
result.push(match.index);
}
if (!hasChildArray(result)) {
return [];
}
//
return result;
}
/**
* find nearest symbol in a content from specified index ...
*
* @param {string|string[]} candidates specifies which symbols to find ...
* @param {string} content te content for seasrch ...
* @param {number} startFromIndex the index of start position ...
* @returns
*/
function findNearest(
candidates,
content = '',
startFromIndex = 0
) {
//
// Validate Args ...
if (
!isValidArg(content) ||
!isValidArg(candidates) ||
!isValidArg(content.trim())
) {
return '';
}
//
// Normalize Content ...
content = content.trim();
//
// Normalize Starts From ...
startFromIndex = startFromIndex < 0 || startFromIndex > content.length - 1 ? 0 : startFromIndex;
//
// Normalize Symbols ...
const normalCandidates = toNormalArray(candidates);
if (!hasChildArray(normalCandidates)) {
return '';
}
//
let nearestIndex = findNearestIndex(
normalCandidates,
content,
startFromIndex
);
if (nearestIndex < 0) {
return '';
}
//
let result = content.substring(
nearestIndex,
nearestIndex + Math.max(...normalCandidates.map(nc => nc.length))
).trim();
return result;
}
/**
* search candidates in content and find nearest one and return it ...
*
* @param {string|string[]} candidates which candidates required to check ...
* @param {string} content the content which required to search candidates ...
* @param {number} startFromIndex the proposed index to start searching content from on ...
* @returns
*/
function findNearestIndex(
candidates = [''],
content = '',
startFromIndex = 0,
ignoreClosedItems = false
) {
//
// Validate Args ...
if (
!isValidArg(content) ||
!isValidArg(candidates)
) {
return -1;
}
//
// Mormalize startFromIndex value ...
startFromIndex = startFromIndex < 0 ?
0 :
startFromIndex > content.length - 1 ?
content.length - 1 :
startFromIndex;
//
// Normalize candidates ...
let normalCandidates = toNormalArray(candidates);
//
if (!!ignoreClosedItems) {
normalCandidates = normalCandidates
.map(c => content.indexOf(
c,
startFromIndex
)
).map(c => +c)
.filter(c => +c > -1);
} else {
normalCandidates = findAllIndexesOutOfCloseds(normalCandidates, content)
.filter(c => c >= startFromIndex);
}
if (!hasChildArray(normalCandidates)) {
return -1;
}
//
let result = -1;
result = Math.min(...normalCandidates);
//
return result;
}
/**
* find close index of specific sign in destination content ...
*
* @param {string} openSymbol open of area sign ...
* @param {string} closeSymbol close of area sign ...
* @param {string} content the destination content for parsing ...
* @param {number} startsFrom an start index of content for start parsing ...
* @returns
*/
function findCloseIndex(
openSymbol = '',
closeSymbol = '',
content = '',
startsFrom = -1
) {
//
// Validate Args ...
if (
startsFrom < 0 ||
!isValidArg(content) ||
!isValidArg(openSymbol) ||
!isValidArg(closeSymbol) ||
openSymbol === closeSymbol ||
!content.includes(openSymbol) ||
!content.includes(closeSymbol) ||
startsFrom > content.length - 1
) {
return -1;
}
//
let result = -1;
//
let index = startsFrom;
const openSignStack = [];
while (index < content.length) {
//
const openCandidate = content.substring(index, index + openSymbol.length);
const closeCandidate = content.substring(index, index + closeSymbol.length);
//
if (openCandidate === openSymbol) {
openSignStack.push(index);
} else if (closeCandidate === closeSymbol) {
//
if (openSignStack.length > 0) {
openSignStack.pop();
}
//
if (openSignStack.length === 0) {
result = index;
break;
}
}
//
index++;
}
//
return result;
}
/**
* find closed contents of specific sign in destination content ...
*
* @param {string} openSymbol open of area sign ...
* @param {string} closeSymbol close of area sign ...
* @param {string} content the destination content for parsing ...
* @param {number} startsFrom an start index of content for start parsing ...
* @returns
*/
function findClosedContent(
openSymbol = '',
closeSymbol = '',
content = '',
startsFrom = 0,
) {
//
let result = [{
start: -1,
end: -1,
content: ''
}];
result.pop();
//
// Validate Args ...
if (
!isValidArg(content) ||
!isValidArg(openSymbol) ||
!isValidArg(closeSymbol) ||
!content.includes(openSymbol) ||
!content.includes(closeSymbol) ||
openSymbol.length >= content.length ||
closeSymbol.length >= content.length
) {
return result;
}
//
// Normalize Start From ...
startsFrom = startsFrom < 0 || startsFrom >= content.length ? 0 : startsFrom;
//
let canContinue = true;
while (!!canContinue) {
//
let openSymbolIndex = content.indexOf(openSymbol, startsFrom);
if (openSymbolIndex < 0) {
//
canContinue = false;
continue;
}
//
let closeSymbolIndex = findCloseIndex(
openSymbol,
closeSymbol,
content,
openSymbolIndex
);
if (closeSymbolIndex < 0) {
//
canContinue = false;
continue;
}
if (content.charAt(closeSymbolIndex) !== closeSymbol) {
closeSymbolIndex++;
}
//
// Prevent ${} string interpolations ...
if (
openSymbol === '{' &&
openSymbolIndex - 1 >= 0
) {
//
const prevChar = content.charAt(openSymbolIndex - 1);
if (prevChar === '$') {
continue;
}
}
//
const item = content
.substring(openSymbolIndex, closeSymbolIndex + 1)
.trim();
startsFrom = closeSymbolIndex + 1;
result.push({
start: openSymbolIndex,
end: closeSymbolIndex,
content: item
});
}
//
if (!hasChildArray(result)) {
return result;
}
//
return result;
}
/**
* extract a collection of closed contents exists in a content ...
*
* @param symbols a collection of open and close contents ...
* @param {string} content a content for searching inside it ...
* @returns a collection of closed content ...
*/
function findClosedContents(
symbols = [
{
openSymbol: '',
closeSymbol: ''
}
],
content = ''
) {
//
let result = [{
start: -1,
end: -1,
content: ''
}];
result.pop();
//
if (
!isValidArg(content) ||
!hasChildArray(symbols)
) {
return [];
}
//
symbols.forEach(symbol => {
//
const closedContent = findClosedContent(
symbol.openSymbol,
symbol.closeSymbol,
content
);
//
if (hasChildArray(closedContent)) {
result.push(
...closedContent
);
}
});
//
return result;
}
/**
* find all string content closed items ...
*
* @param {string} content a content which going to search ...
* @returns a collection of index descriptors ...
*/
function findClosedStrings(content = '') {
//
// Validate Args ...
if (!isValidArg(content)) {
return [];
}
//
// there are 3 types of strings ...
// ' " and `
//
const token1 = '\'';
const token1Stack = [0];
token1Stack.pop();
//
const token2 = '"';
const token2Stack = [0];
token2Stack.pop();
//
const token3 = '`';
const token3Stack = [0];
token3Stack.pop();
//
const result = [
{
start: -1,
end: -1,
content: ''
}
];
result.pop();
//
for (let i = 0; i < content.length; i++) {
//
const currentChart = content.charAt(i);
//
//#region Token 1 ...
if (currentChart === token1) {
//
if (!hasChildArray(token1Stack)) {
token1Stack.push(i);
} else {
//
const start = token1Stack.pop();
const end = i + 1;
const pContent = content.substring(start, end);
result.push({
start,
end,
content: pContent
});
}
}
//#endregion
//
//#region Token 2 ...
if (currentChart === token2) {
//
if (!hasChildArray(token2Stack)) {
token2Stack.push(i);
} else {
//
const start = token2Stack.pop();
const end = i + 1;
const pContent = content.substring(start, end);
result.push({
start,
end,
content: pContent
});
}
}
//#endregion
//
//#region Token 3 ...
if (currentChart === token3) {
//
if (!hasChildArray(token3Stack)) {
token3Stack.push(i);
} else {
//
const start = token3Stack.pop();
const end = i + 1;
const pContent = content.substring(start, end);
result.push({
start,
end,
content: pContent
});
}
}
//#endregion
}
//
return result;
}
/**
* find container indexes from within indexes ...
*
* @param {...{start: number, end: number}} index the collection of indexes to find beiggers inside ...
* @returns
*/
function findContainerIndexes(...index) {
//
let result = [
{
start: -1,
end: -1,
content: ''
}
];
result.pop();
//
let concatedIndexes = [];
for (let idx of index) {
//
// Index Childs ...
for (let iix of idx) {
//
// Check idx is standard ...
if (
!iix ||
!iix.end ||
!iix.start ||
iix.start > iix.end
) {
continue;
}
//
// Check index inside another index ...
concatedIndexes.push(iix);
}
}
//
if (!hasChildArray(concatedIndexes)) {
return result;
}
//
for (let ccIdx of concatedIndexes) {
//
const isInside = isIndexInside(ccIdx, ...concatedIndexes);
if (isInside) {
continue;
}
//
if (hasChildArray(result)) {
//
const isInsideResult = isIndexInside(ccIdx, ...result);
if (isInsideResult) {
continue;
}
}
//
result.push(ccIdx);
}
//
return result;
}
/**
* find all tokens indexes inside a content which they are not inside closed items ...
*
* @param {string|string[]} tokens the tokens which require to search ...
* @param {string} content the content which using to search ...
* @returns
*/
function findAllIndexesOutOfCloseds1(
tokens,
content,
) {
//
// Validate Args ...
if (!isValidArg(content)) {
return [];
}
//
// Extract token Indexes ...
const tokensIndexes = findAllIndexes(tokens, content);
if (!hasChildArray(tokensIndexes)) {
return [];
}
//
// Extract Closed Objects Indexes ...
const closedArrays = findClosedContent('[', ']', content);
const closedObjects = findClosedContent('{', '}', content);
const closedStrings = findClosedStrings(content);
if (
!hasChildArray(closedObjects) &&
!hasChildArray(closedArrays) &&
!hasChildArray(closedStrings)
) {
return tokensIndexes;
}
//
// find bigger sloded ...
let containerClosedItems = findContainerIndexes(
closedArrays,
closedObjects,
closedStrings
).filter(i => !isSurroundedString(i.content));
//
let result = [-1];
result.pop();
//
for (let tIdx of tokensIndexes) {
//
let canAdd = true;
for (let ccIndex of containerClosedItems) {
//
canAdd = isInsideIndex(tIdx, ccIndex);
if (canAdd) {
break;
}
}
//
if (!canAdd) {
result.push(tIdx);
}
}
//
return result;
}
/**
* find all tokens indexes inside a content which they are not inside closed items ...
*
* @param {string|string[]} tokens the tokens which require to search ...
* @param {string} content the content which using to search ...
* @returns
*/
function findAllIndexesOutOfCloseds(
tokens,
content,
) {
//
// Define Result ...
let result = [-1];
result.pop();
//
// Validate Args ...
if (!isValidArg(content)) {
return [];
}
//
// Normalize Tokens ...
const normalizeTokens = toNormalArray(tokens);
if (!hasChildArray(normalizeTokens)) {
return result;
}
//
// Extract Closed Objects Indexes ...
let openSymbols = [
'{',
'[',
'\'',
'"',
'`'
];
let closeSymbols = [
'}',
']',
'\'',
'"',
'`'
];
let openStack = [];
let lastOpenSymbol = '';
let lastClosedIndex = -1;
for (let i = 0; i < content.length; i++) {
//
const prevChar = content.charAt(i - 1) || '';
const char = content.charAt(i);
const nextChar = content.charAt(i + 1) || '';
//
const isToken = normalizeTokens.includes(char);
const isOpenSymbol = openSymbols.includes(char);
const isCloseSymbol = closeSymbols.includes(char);
//
if (isOpenSymbol && lastOpenSymbol !== char) {
openStack.push(i);
lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? char : lastOpenSymbol;
} else if (isCloseSymbol) {
//
lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? '' : lastOpenSymbol;
let lastPop = openStack.pop();
if (openStack.length === 0) {
lastClosedIndex = lastPop;
}
} else if (isToken) {
if (
i > lastClosedIndex &&
openStack.length === 0
) {
result.push(i);
}
}
}
//
return result;
}
//#endregion
//
//#region Validator Actions ...
/**
* check specified value is Valid URL Address or not ...
*
* @param {string} value specified string which required to check
* @returns {boolean}
*/
function isValidURL(value = "") {
//
if (!isValidArg(value)) {
return false;
}
const pattern = new RegExp(
'^([a-zA-Z]+:\\/\\/)?' + // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
'(\\#[-a-z\\d_]*)?$', // fragment locator
'i'
);
//
const result = pattern.test(value);
return result;
}
/**
* check specified value is Valid URL Address or not ...
*
* @param {string} value specified string which required to check
*/
function isValidEmail(value = "") {
//
if (!isValidArg(value)) {
return false;
}
//
const pattern = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/gim;
//
const result = pattern.test(value);
return result;
}
//#endregion
//
//#region Normallizers ...
/**
* normallize an string ...
*
* @param {string} value specified value ...
* @returns {string}
*/
function toNormalString(value = "") {
//
if (!XTypeTools.isString(value)) {
value = "";
}
//
const result = value
.trim()
.toLowerCase();
//
return result;
}
//#endregion
//
//#region Beautifiers ...
/**
* converts an object to string based on json and beautify result ...
*
* @param {any} object
* @returns {string}
*/
function beautifyJSON(object = undefined) {
//
// TODO: Complete this ...
let result = "";
//
// validate object ...
if (object === undefined) {
return result;
}
//
// Convert result ...
result = JSON.stringify(
object,
null,
4
);
//
return result;
}
//#endregion
//
//#region Module Exports ...
module.exports = {
//
endsWidth,
surroundBy,
isValidArg,
isValidArgs,
toNormalArray,
hasChildArray,
toStringExpression,
//
sliceContent,
clearContent,
clearSurround,
clearArraySurround,
clearObjectSurround,
//
isSurrounded,
isIndexInside,
isInsideIndex,
isKeyValueType,
isSurroundedArray,
isSurroundedString,
isSurroundedObject,
//
findNearest,
findAllIndexes,
findCloseIndex,
findNearestIndex,
findClosedContent,
findClosedStrings,
findClosedContents,
findAllIndexesOutOfCloseds,
//
// Validator Actions ...
isValidURL,
isValidEmail,
//
// Normallizers ...
toNormalString,
//
beautifyJSON,
}
//#endregion