From fdc93ef795d9d9745a9529eb8d82542afbb5c734 Mon Sep 17 00:00:00 2001 From: Joel Guerra Date: Mon, 24 Jun 2024 14:58:52 +0200 Subject: [PATCH] fix: link patterns lint --- .gitignore | 3 +- packages/main/.gitignore | 2 +- .../Jaeger-ui/src/model/link-patterns.tsx | 363 ++++++++++-------- 3 files changed, 197 insertions(+), 171 deletions(-) diff --git a/.gitignore b/.gitignore index 941bcae7..915a1ca6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /node_modules/* dist -server \ No newline at end of file +server +*.cookie \ No newline at end of file diff --git a/packages/main/.gitignore b/packages/main/.gitignore index 4bbc0119..e92fcc47 100644 --- a/packages/main/.gitignore +++ b/packages/main/.gitignore @@ -24,4 +24,4 @@ dist-ssr *.sw? *.env #turbo generated cookie files -.cookie \ No newline at end of file +*.cookie \ No newline at end of file diff --git a/packages/main/src/components/DataViews/components/Traces/Jaeger-ui/src/model/link-patterns.tsx b/packages/main/src/components/DataViews/components/Traces/Jaeger-ui/src/model/link-patterns.tsx index 7fb5e1e4..7d26ee57 100644 --- a/packages/main/src/components/DataViews/components/Traces/Jaeger-ui/src/model/link-patterns.tsx +++ b/packages/main/src/components/DataViews/components/Traces/Jaeger-ui/src/model/link-patterns.tsx @@ -12,53 +12,60 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { uniq as _uniq } from 'lodash'; -import memoize from 'lru-memoize'; +import { uniq as _uniq } from "lodash"; +import memoize from "lru-memoize"; import DOMPurify from "isomorphic-dompurify"; -import { TNil } from '../types'; -import { TraceSpan, TraceLink, TraceKeyValuePair, Trace } from '../types/trace'; -import { getConfigValue } from '../utils/config/get-config'; +import { TNil } from "../types"; +import { TraceSpan, TraceLink, TraceKeyValuePair, Trace } from "../types/trace"; +import { getConfigValue } from "../utils/config/get-config"; -import { getParent } from './span'; +import { getParent } from "./span"; const parameterRegExp = /#\{([^{}]*)\}/g; type ProcessedTemplate = { - parameters: string[]; - template: (template: { [key: string]: any }) => string; + parameters: string[]; + template: (template: { [key: string]: any }) => string; }; type ProcessedLinkPattern = { - object: any; - type: (link: string) => boolean; - key: (link: string) => boolean; - value: (value: any) => boolean; - url: ProcessedTemplate; - text: ProcessedTemplate; - parameters: string[]; + object: any; + type: (link: string) => boolean; + key: (link: string) => boolean; + value: (value: any) => boolean; + url: ProcessedTemplate; + text: ProcessedTemplate; + parameters: string[]; }; type TLinksRV = Array<{ url: string; text: string }>; function getParamNames(str: string) { - const names = new Set(); - str.replace(parameterRegExp, (match, name) => { - names.add(name); - return match; - }); - return Array.from(names); + const names = new Set(); + str.replace(parameterRegExp, (match, name) => { + names.add(name); + return match; + }); + return Array.from(names); } -function stringSupplant(str: string, encodeFn: (unencoded: any) => string, map: Record) { - return str.replace(parameterRegExp, (_, name) => { - const value = map[name]; - return value == null ? '' : encodeFn(value); - }); +function stringSupplant( + str: string, + encodeFn: (unencoded: any) => string, + map: Record +) { + return str.replace(parameterRegExp, (_, name) => { + const value = map[name]; + return value == null ? "" : encodeFn(value); + }); } -export function processTemplate(template: unknown, encodeFn: (unencoded: any) => string): ProcessedTemplate { - if (typeof template !== 'string') { - /* +export function processTemplate( + template: unknown, + encodeFn: (unencoded: any) => string +): ProcessedTemplate { + if (typeof template !== "string") { + /* // kept on ice until #123 is implemented: if (template && Array.isArray(template.parameters) && (typeof template.template === 'function')) { @@ -66,22 +73,22 @@ export function processTemplate(template: unknown, encodeFn: (unencoded: any) => } */ - throw new Error('Invalid template'); - } - return { - parameters: getParamNames(template), - template: stringSupplant.bind(null, template, encodeFn), - }; + throw new Error("Invalid template"); + } + return { + parameters: getParamNames(template), + template: stringSupplant.bind(null, template, encodeFn), + }; } export function createTestFunction(entry: any) { - if (typeof entry === 'string') { - return (arg: unknown) => arg === entry; - } - if (Array.isArray(entry)) { - return (arg: unknown) => entry.indexOf(arg) > -1; - } - /* + if (typeof entry === "string") { + return (arg: unknown) => arg === entry; + } + if (Array.isArray(entry)) { + return (arg: unknown) => entry.indexOf(arg) > -1; + } + /* // kept on ice until #123 is implemented: if (entry instanceof RegExp) { @@ -92,162 +99,180 @@ export function createTestFunction(entry: any) { } */ - if (entry == null) { - return () => true; - } - throw new Error(`Invalid value: ${entry}`); + if (entry == null) { + return () => true; + } + throw new Error(`Invalid value: ${entry}`); } const identity = (a: any): typeof a => a; export function processLinkPattern(pattern: any): ProcessedLinkPattern | TNil { - try { - const url = processTemplate(pattern.url, encodeURIComponent); - const text = processTemplate(pattern.text, identity); - return { - object: pattern, - type: createTestFunction(pattern.type), - key: createTestFunction(pattern.key), - value: createTestFunction(pattern.value), - url, - text, - parameters: _uniq(url.parameters.concat(text.parameters)), - }; - } catch (error) { - // eslint-disable-next-line no-console - console.error(`Ignoring invalid link pattern: ${error}`, pattern); - return null; - } + try { + const url = processTemplate(pattern.url, encodeURIComponent); + const text = processTemplate(pattern.text, identity); + return { + object: pattern, + type: createTestFunction(pattern.type), + key: createTestFunction(pattern.key), + value: createTestFunction(pattern.value), + url, + text, + parameters: _uniq(url.parameters.concat(text.parameters)), + }; + } catch (error) { + // eslint-disable-next-line no-console + console.error(`Ignoring invalid link pattern: ${error}`, pattern); + return null; + } } export function getParameterInArray(name: string, array: TraceKeyValuePair[]) { - if (array) { - return array.find((entry) => entry.key === name); - } - return undefined; + if (array) { + return array.find((entry) => entry.key === name); + } + return undefined; } export function getParameterInAncestor(name: string, span: TraceSpan) { - let currentSpan: TraceSpan | TNil = span; - while (currentSpan) { - const result = getParameterInArray(name, currentSpan.tags) || getParameterInArray(name, currentSpan.process.tags); - if (result) { - return result; + let currentSpan: TraceSpan | TNil = span; + while (currentSpan) { + const result = + getParameterInArray(name, currentSpan.tags) || + getParameterInArray(name, currentSpan.process.tags); + if (result) { + return result; + } + currentSpan = getParent(currentSpan); } - currentSpan = getParent(currentSpan); - } - return undefined; + return undefined; } function callTemplate(template: ProcessedTemplate, data: any) { - return template.template(data); + return template.template(data); } -export function computeTraceLink(linkPatterns: ProcessedLinkPattern[], trace: Trace) { - const result: TLinksRV = []; - const validKeys = (Object.keys(trace) as Array).filter( - (key) => typeof trace[key] === 'string' || trace[key] === 'number' - ); - - linkPatterns - .filter((pattern) => pattern.type('traces')) - .forEach((pattern) => { - const parameterValues: Record = {}; - const allParameters = pattern.parameters.every((parameter) => { - const key = parameter as keyof Trace; - if (validKeys.includes(key)) { - // At this point is safe to access to trace object using parameter variable because - // we validated parameter against validKeys, this implies that parameter a keyof Trace. - parameterValues[parameter] = trace[key]; - return true; - } - return false; - }); - if (allParameters) { - result.push({ - url: callTemplate(pattern.url, parameterValues), - text: callTemplate(pattern.text, parameterValues), +export function computeTraceLink( + linkPatterns: ProcessedLinkPattern[], + trace: Trace +) { + const result: TLinksRV = []; + const validKeys: any = (Object.keys(trace) as Array).filter( + (key) => typeof trace[key] === "string" || trace[key] === "number" + ); + + linkPatterns + .filter((pattern) => pattern.type("traces")) + .forEach((pattern) => { + const parameterValues: Record = {}; + const allParameters = pattern.parameters.every((parameter) => { + const key = parameter as keyof Trace; + if (validKeys.includes(key)) { + // At this point is safe to access to trace object using parameter variable because + // we validated parameter against validKeys, this implies that parameter a keyof Trace. + parameterValues[parameter] = trace[key]; + return true; + } + return false; + }); + if (allParameters) { + result.push({ + url: callTemplate(pattern.url, parameterValues), + text: callTemplate(pattern.text, parameterValues), + }); + } }); - } - }); - return result; + return result; } export function computeLinks( - linkPatterns: ProcessedLinkPattern[], - span: TraceSpan, - items: TraceKeyValuePair[], - itemIndex: number + linkPatterns: ProcessedLinkPattern[], + span: TraceSpan, + items: TraceKeyValuePair[], + itemIndex: number ) { - const item = items[itemIndex]; - let type = 'logs'; - const processTags = span.process.tags === items; - if (processTags) { - type = 'process'; - } - const spanTags = span.tags === items; - if (spanTags) { - type = 'tags'; - } - const result: Array<{ url: string; text: string }> = []; - linkPatterns.forEach((pattern) => { - if (pattern.type(type) && pattern.key(item.key) && pattern.value(item.value)) { - const parameterValues: Record = {}; - const allParameters = pattern.parameters.every((parameter) => { - let entry = getParameterInArray(parameter, items); - if (!entry && !processTags) { - // do not look in ancestors for process tags because the same object may appear in different places in the hierarchy - // and the cache in getLinks uses that object as a key - entry = getParameterInAncestor(parameter, span); - } - if (entry) { - parameterValues[parameter] = entry.value; - return true; - } - // eslint-disable-next-line no-console - console.warn( - DOMPurify.sanitize(`Skipping link pattern, missing parameter ${parameter} for key ${item.key} in ${type}.`), - pattern.object - ); - return false; - }); - if (allParameters) { - result.push({ - url: callTemplate(pattern.url, parameterValues), - text: callTemplate(pattern.text, parameterValues), - }); - } - } - }); - return result; -} - -export function createGetLinks(linkPatterns: ProcessedLinkPattern[], cache: WeakMap) { - return (span: TraceSpan, items: TraceKeyValuePair[], itemIndex: number) => { - if (linkPatterns.length === 0) { - return []; - } const item = items[itemIndex]; - let result = cache.get(item); - if (!result) { - result = computeLinks(linkPatterns, span, items, itemIndex); - cache.set(item, result); + let type = "logs"; + const processTags = span.process.tags === items; + if (processTags) { + type = "process"; } + const spanTags = span.tags === items; + if (spanTags) { + type = "tags"; + } + const result: Array<{ url: string; text: string }> = []; + linkPatterns.forEach((pattern) => { + if ( + pattern.type(type) && + pattern.key(item.key) && + pattern.value(item.value) + ) { + const parameterValues: Record = {}; + const allParameters = pattern.parameters.every((parameter) => { + let entry = getParameterInArray(parameter, items); + if (!entry && !processTags) { + // do not look in ancestors for process tags because the same object may appear in different places in the hierarchy + // and the cache in getLinks uses that object as a key + entry = getParameterInAncestor(parameter, span); + } + if (entry) { + parameterValues[parameter] = entry.value; + return true; + } + // eslint-disable-next-line no-console + console.warn( + DOMPurify.sanitize( + `Skipping link pattern, missing parameter ${parameter} for key ${item.key} in ${type}.` + ), + pattern.object + ); + return false; + }); + if (allParameters) { + result.push({ + url: callTemplate(pattern.url, parameterValues), + text: callTemplate(pattern.text, parameterValues), + }); + } + } + }); return result; - }; } -const processedLinks: ProcessedLinkPattern[] = (getConfigValue('linkPatterns') || []) - .map(processLinkPattern) - .filter(Boolean); +export function createGetLinks( + linkPatterns: ProcessedLinkPattern[], + cache: WeakMap +) { + return (span: TraceSpan, items: TraceKeyValuePair[], itemIndex: number) => { + if (linkPatterns.length === 0) { + return []; + } + const item = items[itemIndex]; + let result = cache.get(item); + if (!result) { + result = computeLinks(linkPatterns, span, items, itemIndex); + cache.set(item, result); + } + return result; + }; +} + +const processedLinks: ProcessedLinkPattern[] = ( + getConfigValue("linkPatterns") || [] +) + .map(processLinkPattern) + .filter(Boolean); -export const getTraceLinks: (trace: Trace | undefined) => TLinksRV = memoize(10)((trace: Trace | undefined) => { - const result: TLinksRV = []; - if (!trace) { - return result; - } - return computeTraceLink(processedLinks, trace); +export const getTraceLinks: (trace: Trace | undefined) => TLinksRV = memoize( + 10 +)((trace: Trace | undefined) => { + const result: TLinksRV = []; + if (!trace) { + return result; + } + return computeTraceLink(processedLinks, trace); }); export default createGetLinks(processedLinks, new WeakMap());