/*! * SAPUI5 * Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. */ import { Value as RawValue } from "../../sina/types"; import { AttributeType } from "../../sina/AttributeType"; import { ComparisonOperator } from "../../sina/ComparisonOperator"; export async function readFile(path: string): Promise { try { if (typeof window === "undefined") { // Node.js environment const fs = await import("node:fs"); const url = await import("node:url"); const pathLib = await import("node:path"); const __filename = url.fileURLToPath(import.meta.url); const __dirname = pathLib.dirname(__filename); const elisaPath = pathLib.join(__dirname, "../../../../../../../.."); //path = path.replace("/$elisa$", elisaPath); path = elisaPath + "/dist/" + path; const data = fs.readFileSync(path, { encoding: "utf-8" }).toString(); return data; } else { // browser environment const response = await fetch(path); if (!response.ok) { throw new Error(`Failed to fetch file: ${response.statusText}`); } return await response.text(); } } catch (error) { console.error(`Error reading file at ${path}:`, error); throw error; } } export function isMatched( value1: RawValue, value2: RawValue, operator: ComparisonOperator, caseSensitive?: boolean ): boolean { if (typeof value1 !== typeof value2) { return false; } const type = typeof value1; // number and date operations: Eq, Ne, Ge, Le, Gt, Lt if (type === "number" || (value1 instanceof Date && value2 instanceof Date)) { switch (operator) { case ComparisonOperator.Eq: return value1 === value2; case ComparisonOperator.Ne: return value1 !== value2; case ComparisonOperator.Ge: return value1 >= value2; case ComparisonOperator.Le: return value1 <= value2; case ComparisonOperator.Gt: return value1 > value2; case ComparisonOperator.Lt: return value1 < value2; } } // string operations: Eq, Ne, Co, Bw, Ew, ValueHelp if (type === "string") { return isStringMatched(value1 as string, value2 as string, operator, caseSensitive); } } function isStringMatched( value1: string, value2: string, operator: ComparisonOperator, caseSensitive?: boolean ): boolean { const pattern = value2 .replace(/[.+?^${}()|[\]\\]/g, "\\$&") // escape everything except * .replace(/\*/g, ".*"); // replace * with .* const cs = caseSensitive !== true ? "i" : ""; let regExp; switch (operator) { case ComparisonOperator.Eq: regExp = new RegExp(`^${pattern}$`, cs); return regExp.test(value1); case ComparisonOperator.Ne: regExp = new RegExp(`^(?!${pattern}$).*`, cs); return regExp.test(value1); case ComparisonOperator.Co: regExp = new RegExp(pattern, cs); return regExp.test(value1); case ComparisonOperator.Bw: case ComparisonOperator.ValueHelp: regExp = new RegExp(`^${pattern}`, cs); return regExp.test(value1); case ComparisonOperator.Ew: regExp = new RegExp(`${pattern}$`, cs); return regExp.test(value1); default: // unsupported operators Ge, Le, Gt, Lt // regExp = new RegExp(`^${pattern}`, cs); return false; } } export function getMatchedStringValues( stringValues: string[], searchTerm: string, caseSensitive?: boolean ): string[] { if (isStarString(searchTerm)) { return stringValues; } if (!isNotEmptyString(searchTerm)) { return stringValues; } // 1. split searchTerm by white space into multiple sub-terms const subTerms = getSubTerms(searchTerm); const matchedStringValueMap = {}; // 2. build matched string value map for each sub-term for (const term of subTerms) { matchedStringValueMap[term] = stringValues.filter((sValue) => isStringMatched(sValue, term, ComparisonOperator.Co, caseSensitive) ); } // 3. return matched string values across all sub-terms if (subTerms.some((t) => (matchedStringValueMap[t]?.length ?? 0) === 0)) { // some subTerm has no matches return []; } else { // marge matched string values const matchedStringValues = []; for (const key in matchedStringValueMap) { const values = matchedStringValueMap[key]; for (let i = 0; i < values.length; i++) { const value = values[i]; if (!matchedStringValues.includes(value)) { matchedStringValues.push(value); } } } return matchedStringValues; } } export function formatRawValue(stringValue: string, type: AttributeType): RawValue { switch (type) { case AttributeType.Double: return parseFloat(stringValue) || 0; case AttributeType.Integer: return parseInt(stringValue, 10) || 0; case AttributeType.String: return stringValue; case AttributeType.ImageUrl: return stringValue; case AttributeType.ImageBlob: return stringValue; case AttributeType.GeoJson: return stringValue; case AttributeType.Date: { const date = isNaN(new Date(stringValue).getTime()) ? new Date(0) : new Date(stringValue); return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate(); } case AttributeType.Time: return stringValue; case AttributeType.Timestamp: { const date = isNaN(new Date(stringValue).getTime()) ? new Date(0) : new Date(stringValue); return date; } case AttributeType.Group: return stringValue; default: return stringValue; } } export function formatHighlightedValue(stringValue: string, searchTerm: string): string { if (stringValue === undefined) { return ""; } if (isStarString(searchTerm)) { return stringValue; } if (!isNotEmptyString(searchTerm)) { return stringValue; } const terms = getSubTerms(searchTerm); if (terms.length === 0) { return stringValue; } let highlightedValue = stringValue; for (const term of terms) { const regexp = new RegExp(`(${term})`, "gi"); highlightedValue = highlightedValue.replace(regexp, "$1"); } return highlightedValue; } export function format10Power(value: number, isCeil?: boolean): number { // isCeil NOT true: find biggest 10 power number, smaller than value // isCeil true: find smallest 10 power number, bigger than value const digits = isCeil ? Math.trunc(value).toString().split("").map(Number).length : Math.trunc(value).toString().split("").map(Number).length - 1; if (isCeil) { return Math.pow(10, digits); } else { return digits === 0 ? 0 : Math.pow(10, digits); } } export function isStarString(value: string): boolean { return /^\*+$/.test(value); } export function isNotEmptyString(value: string): boolean { return typeof value === "string" && value.trim().length > 0; } export function getSubTerms(searchTerm: string): string[] { const term = (searchTerm ?? "").trim(); if (!term) return []; // remove special characters from each term return term .split(/\s+/) .map((t) => t.replace(/[*?#^${}+?|/]/g, "")) // remove regex special characters .filter((t) => t.length > 0); }