1// Copyright 2021 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14import { EditorState } from '@codemirror/state';
15import { SyntaxNode } from '@lezer/common';
16import {
17  And,
18  BinaryExpr,
19  BinModifiers,
20  GroupingLabel,
21  GroupingLabelList,
22  GroupingLabels,
23  GroupLeft,
24  GroupRight,
25  On,
26  OnOrIgnoring,
27  Or,
28  Unless,
29} from '../grammar/parser.terms';
30import { VectorMatchCardinality, VectorMatching } from '../types';
31import { containsAtLeastOneChild, retrieveAllRecursiveNodes } from './path-finder';
32
33export function buildVectorMatching(state: EditorState, binaryNode: SyntaxNode): VectorMatching | null {
34  if (!binaryNode || binaryNode.type.id !== BinaryExpr) {
35    return null;
36  }
37  const result: VectorMatching = {
38    card: VectorMatchCardinality.CardOneToOne,
39    matchingLabels: [],
40    on: false,
41    include: [],
42  };
43  const binModifiers = binaryNode.getChild(BinModifiers);
44  if (binModifiers) {
45    const onOrIgnoring = binModifiers.getChild(OnOrIgnoring);
46    if (onOrIgnoring) {
47      result.on = onOrIgnoring.getChild(On) !== null;
48      const labels = retrieveAllRecursiveNodes(onOrIgnoring.getChild(GroupingLabels), GroupingLabelList, GroupingLabel);
49      if (labels.length > 0) {
50        for (const label of labels) {
51          result.matchingLabels.push(state.sliceDoc(label.from, label.to));
52        }
53      }
54    }
55
56    const groupLeft = binModifiers.getChild(GroupLeft);
57    const groupRight = binModifiers.getChild(GroupRight);
58    if (groupLeft || groupRight) {
59      result.card = groupLeft ? VectorMatchCardinality.CardManyToOne : VectorMatchCardinality.CardOneToMany;
60      const includeLabels = retrieveAllRecursiveNodes(binModifiers.getChild(GroupingLabels), GroupingLabelList, GroupingLabel);
61      if (includeLabels.length > 0) {
62        for (const label of includeLabels) {
63          result.include.push(state.sliceDoc(label.from, label.to));
64        }
65      }
66    }
67  }
68
69  const isSetOperator = containsAtLeastOneChild(binaryNode, And, Or, Unless);
70  if (isSetOperator && result.card === VectorMatchCardinality.CardOneToOne) {
71    result.card = VectorMatchCardinality.CardManyToMany;
72  }
73  return result;
74}
75