scopeName: source.apollo.connectors.graphql
# inject these rules into source.graphql#graphql-directive, before all other patterns (:L), ignoring strings and comments
injectionSelector: L:meta.embedded.block.directive.graphql -string -comment
patterns:
  - include: "#connector-directive"
repository:
  # if we encounter a `@connect` or `@source` directive, move forward into this set of rules, otherwise it will just follow the default graphql rules
  connector-directive:
    begin: ((@)\s*(connect|source))
    end: (?=.)
    applyEndPatternLast: 1
    beginCaptures:
      "1":
        name: entity.name.function.directive.connect.graphql
    patterns:
      - include: "#connector-arguments"
      - include: source.graphql#graphql-comment
      - include: source.graphql#literal-quasi-embedded
      - include: source.graphql#graphql-skip-newlines
  # a variation of source.graphql#graphql-arguments
  connector-arguments:
    name: meta.arguments.connect.graphql
    begin: \s*(\()
    end: \s*(\))
    beginCaptures:
      "1":
        name: meta.brace.round.directive.graphql
    endCaptures:
      "1":
        name: meta.brace.round.directive.graphql
    patterns:
      - include: source.graphql#graphql-comment
      # this was added
      - include: "#connector-connectors-mapping-argument"
      # this was added
      - include: "#connector-argument-http"
      # this was added
      - include: "#connector-string-connectors-mapping-argument"
      # this is also present in the original source.graphql#graphql-arguments, but as an inlined pattern
      # moved into it's own rule here for readability
      - include: "#graphql-argument"
      - include: source.graphql#literal-quasi-embedded
  # based to #graphql-argument, but only matching `selection` arguments
  # with a sub-pattern to match """ blocks and embed the
  # source.apollo.connectors.mapping grammar into those
  connector-connectors-mapping-argument:
    name: meta.argument.connect.connectors.mapping.graphql
    begin: \s*(selection)(?:\s*(:))
    end: (?=\s*(?:(?:([_A-Za-z][_0-9A-Za-z]*)\s*(:))|\)))|\s*(,)
    beginCaptures:
      "1":
        name: variable.parameter.graphql
      "2":
        name: punctuation.colon.graphql
    endCaptures:
      "3":
        name: punctuation.comma.graphql
    patterns:
      - contentName: meta.embedded.block.connectors.mapping.graphql
        begin: (("""))
        end: (("""))
        beginCaptures:
          "1":
            name: string.quoted.double.graphql
          "2":
            name: punctuation.definition.string.begin.graphql
        endCaptures:
          "1":
            name: string.quoted.double.graphql
          "2":
            name: punctuation.definition.string.end.graphql
        patterns:
          - include: source.apollo.connectors.mapping
      - contentName: meta.embedded.line.connectors.mapping.graphql
        begin: (?<!")(("))(?!")
        end: (?<!")(("))(?!")
        beginCaptures:
          "1":
            name: string.quoted.double.graphql
          "2":
            name: punctuation.definition.string.begin.graphql
        endCaptures:
          "1":
            name: string.quoted.double.graphql
          "2":
            name: punctuation.definition.string.end.graphql
        patterns:
          - include: source.apollo.connectors.mapping
      - include: source.graphql#graphql-comment
      - include: source.graphql#graphql-skip-newlines
  # based to #graphql-argument, but only matching `http` arguments
  connector-argument-http:
    name: meta.argument.connect.http.graphql
    begin: \s*(http)\s*(:)
    end: (?=\s*(?:(?:([_A-Za-z][_0-9A-Za-z]*)\s*(:))|\)))|\s*(,)
    beginCaptures:
      "1":
        name: variable.parameter.graphql
      "2":
        name: punctuation.colon.graphql
    endCaptures:
      "3":
        name: punctuation.comma.graphql
    patterns:
      # we know that the child of this can not be a full #graphql-value, but only an object
      # and we want to look for connectors-specific keys inside of that
      - include: "#http-object-value"
      - include: source.graphql#graphql-comment
      - include: source.graphql#literal-quasi-embedded
  # based on source.graphql#graphql-object-value
  http-object-value:
    patterns:
      - name: meta.objectvalues.connect.http.graphql
        begin: \s*({)
        end: \s*(})
        beginCaptures:
          "1":
            name: meta.brace.curly.graphql
        endCaptures:
          "1":
            name: meta.brace.curly.graphql
        patterns:
          # this was added for GET/POST/PUT/PATCH/DELETE
          - include: "#connector-string-connectors-mapping-argument"
          # this was added for headers
          - include: "#connector-array-connectors-mapping-headers"
          # this was added for body
          - include: "#http-object-connectors-mapping-property"
          # original child patterns of source.graphql#graphql-object-value
          - include: source.graphql#graphql-object-field
          - include: source.graphql#graphql-value
  # handling for @connect(http: { body: """ ... """ })
  http-object-connectors-mapping-property:
    patterns:
      - name: meta.argument.connect.body.connectors.mapping.graphql
        contentName: meta.embedded.block.connectors.mapping.graphql
        begin: \s*(body)\s*(:)\s*(("""))
        end: (("""))
        beginCaptures:
          "1":
            name: variable.parameter.graphql
          "2":
            name: punctuation.colon.graphql
          "3":
            name: string.quoted.double.graphql
          "4":
            name: punctuation.definition.string.begin.graphql
        endCaptures:
          "1":
            name: string.quoted.double.graphql
          "2":
            name: punctuation.definition.string.end.graphql
        patterns:
          - include: source.apollo.connectors.mapping
      - name: meta.argument.connect.line.connectors.mapping.graphql
        contentName: meta.embedded.line.connectors.mapping.graphql
        begin: \s*(body)\s*(:)\s*(?<!")(("))(?!")
        end: (?<!")(("))(?!")
        beginCaptures:
          "1":
            name: variable.parameter.graphql
          "2":
            name: punctuation.colon.graphql
          "3":
            name: string.quoted.double.graphql
          "4":
            name: punctuation.definition.string.begin.graphql
        endCaptures:
          "1":
            name: string.quoted.double.graphql
          "2":
            name: punctuation.definition.string.end.graphql
        patterns:
          - include: source.apollo.connectors.mapping
  # handling for @connect(GET: " ... ")
  connector-array-connectors-mapping-headers:
    name: meta.connect.headers
    begin: \s*((headers))(?:\s*(:))
    beginCaptures:
      "1":
        name: string.unquoted.graphql
      "2":
        name: variable.object.key.graphql
    end: (?<=\])
    applyEndPatternLast: 1
    patterns:
      - name: meta.listvalues.graphql
        begin: (\[)
        end: (])
        beginCaptures:
          "1":
            name: meta.brace.square.graphql
        endCaptures:
          "1":
            name: meta.brace.square.graphql
        patterns:
          - name: meta.objectvalues.graphql
            begin: \s*({)
            end: \s*(})
            beginCaptures:
              "1":
                name: meta.brace.curly.graphql
            endCaptures:
              "1":
                name: meta.brace.curly.graphql
            patterns:
              - begin: (\w+)\s*(:)
                end: (?=\s*(?:(?:([_A-Za-z][_0-9A-Za-z]*)\s*(:))|[\)}]))|\s*(,)
                beginCaptures:
                  "1":
                    name: variable.object.key.graphql
                  "2":
                    name: punctuation.graphql
                patterns:
                  - include: source.apollo.connectors.mapping#JSONSelectionString
                  - include: source.graphql#graphql-comment
                  - include: source.graphql#graphql-skip-newlines
              - include: source.graphql#graphql-comment
              - include: source.graphql#graphql-skip-newlines
          - include: "source.graphql#graphql-comment"
          - include: source.graphql#graphql-skip-newlines
  connector-string-connectors-mapping-argument:
    name: meta.argument.connect.string.connectors.mapping.graphql
    contentName: meta.embedded.string.connectors.mapping.graphql
    begin: \s*(GET|POST|PUT|PATCH|DELETE)(?:\s*(:))
    end: (?=\s*(?:(?:([_A-Za-z][_0-9A-Za-z]*)\s*(:))|[\)}]))|\s*(,)
    beginCaptures:
      "1":
        name: variable.parameter.graphql
      "2":
        name: punctuation.colon.graphql
    endCaptures:
      "3":
        name: punctuation.comma.graphql
    patterns:
      - include: source.apollo.connectors.mapping#JSONSelectionString
      - include: "source.graphql#graphql-comment"
      - include: source.graphql#graphql-skip-newlines
  # repeating an inlined pattern that's found within source.graphql#graphql-arguments here to only have minimal changes to graphql.json
  graphql-argument:
    begin: "\\s*([_A-Za-z][_0-9A-Za-z]*)(?:\\s*(:))"
    end: "(?=\\s*(?:(?:([_A-Za-z][_0-9A-Za-z]*)\\s*(:))|\\)))|\\s*(,)"
    beginCaptures:
      "1":
        name: variable.parameter.graphql
      "2":
        name: punctuation.colon.graphql
    endCaptures:
      "3":
        name: punctuation.comma.graphql
    patterns:
      - include: "source.graphql#graphql-value"
      - include: "source.graphql#graphql-comment"
      - include: "source.graphql#graphql-skip-newlines"
