{"version":3,"file":"validation.cjs","sources":["../../../../../src/components/monaco-query-field/monaco-completion-provider/validation.ts"],"sourcesContent":["// Core Grafana history https://github.com/grafana/grafana/blob/v11.0.0-preview/public/app/plugins/datasource/loki/components/monaco-query-field/monaco-completion-provider/validation.ts\nimport { type SyntaxNode } from '@lezer/common';\nimport { type LRParser } from '@lezer/lr';\n\n// Although 0 isn't explicitly provided in the @grafana/lezer-logql library as the error node ID, it does appear to be the ID of error nodes within lezer.\nconst ErrorId = 0;\n\nexport const warningTypes: Record<string, string> = {\n  SubqueryExpr:\n    'This subquery may return only one data point, preventing rate/increase/delta calculations. Use a range at least twice the step size (e.g., [2x:x]).',\n};\n\nenum NodeType {\n  SubqueryExpr = 'SubqueryExpr',\n  Duration = 'NumberDurationLiteralInDurationContext',\n}\n\ninterface ParserIssueBoundary {\n  startLineNumber: number;\n  startColumn: number;\n  endLineNumber: number;\n  endColumn: number;\n  issue: string;\n}\n\ninterface ParseIssue {\n  text: string;\n  node: SyntaxNode;\n}\n\n/**\n * Conceived to work in combination with the MonacoQueryField component.\n * Given an original query, and it's interpolated version, it will return an array of ParserErrorBoundary\n * objects containing nodes which are actual errors. The interpolated version (even with placeholder variables)\n * is required because variables look like errors for Lezer.\n * @internal\n */\nexport function validateQuery(\n  query: string,\n  interpolatedQuery: string,\n  queryLines: string[],\n  parser: LRParser\n): { errors: ParserIssueBoundary[]; warnings: ParserIssueBoundary[] } {\n  if (!query) {\n    return { errors: [], warnings: [] };\n  }\n\n  /**\n   * To provide support to variable interpolation in query validation, we run the parser in the interpolated\n   * query. If there are errors there, we trace them back to the original unparsed query, so we can more\n   * accurately highlight the error in the query, since it's likely that the variable name and variable value\n   * have different lengths. With this, we also exclude irrelevant parser errors that are produced by\n   * lezer not understanding $variables and $__variables, which usually generate 2 or 3 error SyntaxNode.\n   */\n  const { errors: interpolatedErrors, warnings: interpolatedWarnings } = parseQuery(interpolatedQuery, parser);\n  if (!interpolatedErrors.length && !interpolatedWarnings.length) {\n    return { errors: [], warnings: [] };\n  }\n\n  let parseErrors: ParseIssue[] = interpolatedErrors;\n  let parseWarnings: ParseIssue[] = interpolatedWarnings;\n  if (query !== interpolatedQuery) {\n    const { errors: queryErrors, warnings: queryWarnings } = parseQuery(query, parser);\n    parseErrors = interpolatedErrors.flatMap(\n      (interpolatedError) =>\n        queryErrors.filter((queryError) => interpolatedError.text === queryError.text) || interpolatedError\n    );\n    parseWarnings = interpolatedWarnings.flatMap(\n      (interpolatedWarning) =>\n        queryWarnings.filter((queryWarning) => interpolatedWarning.node.from === queryWarning.node.from) ||\n        interpolatedWarning\n    );\n  }\n\n  const errorBoundaries = parseErrors\n    .map((parseError) => findIssueBoundary(query, queryLines, parseError, 'error'))\n    .filter(isValidIssueBoundary);\n  const warningBoundaries = parseWarnings\n    .map((parseWarning) => findIssueBoundary(query, queryLines, parseWarning, 'warning'))\n    .filter(isValidIssueBoundary);\n\n  return {\n    errors: errorBoundaries,\n    warnings: warningBoundaries,\n  };\n}\n\nfunction parseQuery(query: string, parser: LRParser) {\n  const parseErrors: ParseIssue[] = [];\n  const parseWarnings: ParseIssue[] = [];\n\n  const tree = parser.parse(query);\n  tree.iterate({\n    enter: (nodeRef): false | void => {\n      if (nodeRef.type.id === ErrorId) {\n        const node = nodeRef.node;\n        parseErrors.push({ node: node, text: query.substring(node.from, node.to) });\n      }\n\n      if (nodeRef.type.name === NodeType.SubqueryExpr) {\n        const node = nodeRef.node;\n        const durations: string[] = [];\n\n        const children = node.getChildren(NodeType.Duration);\n        for (const child of children) {\n          durations.push(query.substring(child.from, child.to));\n        }\n\n        if (durations.length === 2 && durations[0] === durations[1]) {\n          parseWarnings.push({ node: node, text: query.substring(node.from, node.to) });\n        }\n      }\n    },\n  });\n\n  return { errors: parseErrors, warnings: parseWarnings };\n}\n\nfunction findIssueBoundary(\n  query: string,\n  queryLines: string[],\n  parseError: ParseIssue,\n  issueType: 'error' | 'warning'\n): ParserIssueBoundary | null {\n  if (queryLines.length === 1) {\n    const isEmptyString = parseError.node.from === parseError.node.to;\n    const errorNode = isEmptyString && parseError.node.parent ? parseError.node.parent : parseError.node;\n    let issue: string;\n\n    if (issueType === 'error') {\n      issue = isEmptyString ? query.substring(errorNode.from, errorNode.to) : parseError.text;\n    } else {\n      issue = warningTypes[parseError.node.type.name];\n    }\n\n    return {\n      startLineNumber: 1,\n      startColumn: errorNode.from + 1,\n      endLineNumber: 1,\n      endColumn: errorNode.to + 1,\n      issue,\n    };\n  }\n\n  let startPos = 0,\n    endPos = 0;\n  for (let line = 0; line < queryLines.length; line++) {\n    endPos = startPos + queryLines[line].length;\n\n    if (parseError.node.from > endPos) {\n      startPos += queryLines[line].length + 1;\n      continue;\n    }\n\n    return {\n      startLineNumber: line + 1,\n      startColumn: parseError.node.from - startPos + 1,\n      endLineNumber: line + 1,\n      endColumn: parseError.node.to - startPos + 1,\n      issue: issueType === 'error' ? parseError.text : warningTypes[parseError.node.type.name],\n    };\n  }\n\n  return null;\n}\n\nfunction isValidIssueBoundary(boundary: ParserIssueBoundary | null): boundary is ParserIssueBoundary {\n  return boundary !== null;\n}\n\nexport const placeHolderScopedVars = {\n  __interval: { text: '1s', value: '1s' },\n  __rate_interval: { text: '1s', value: '1s' },\n  __auto: { text: '1s', value: '1s' },\n  __interval_ms: { text: '1000', value: 1000 },\n  __range_ms: { text: '1000', value: 1000 },\n  __range_s: { text: '1', value: 1 },\n  __range: { text: '1s', value: '1s' },\n};\n"],"names":["NodeType"],"mappings":"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"}