tree-sitter-prisma 0.1.1

Primsa grammar for the tree-sitter parsing library
Documentation
// @ts-check

// Reference: https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference
// Reference: https://github.com/prisma/specs/tree/master/schema
// Reference Implementation: https://github.com/prisma/language-tools/tree/master/packages/vscode/syntaxes
// Reference Implementation: https://github.com/pantharshit00/vim-prisma

module.exports = grammar({
  name: 'prisma',
  word: ($) => $.identifier,
  extras: ($) => [/\s/, $.comment, $.document_comment],
  conflicts: ($) => [
    [$._field_array, $._array],
    [$._model_attribute_arg_no_label, $._expression],
    [$._identifier_separated, $._expression],
  ],

  rules: {
    source_file: ($) => repeat1($._block),
    _block: ($) => choice($.key_value_block, $.model_block, $.enum_block),

    key_value_block: ($) => seq(choice('datasource', 'generator'), $.identifier, '{', $._key_value_block_content, '}'),
    _key_value_block_content: ($) => repeat1($.key_value),

    key_value: ($) => seq($.key, '=', $.value),
    key: ($) => seq($.identifier),
    value: ($) => seq($._expression),

    model_block: ($) => seq('model', $.identifier, '{', $._model_block_content, '}'),
    _model_block_content: ($) => repeat1(choice($.model_field, $.model_multi_attribute)),
    model_field: ($) => seq(field('field_name', $.identifier), $.field_type, repeat($.model_single_attribute)),

    enum_block: ($) => seq('enum', $.identifier, '{', $._enum_block_content, '}'),
    _enum_block_content: ($) => repeat1($.identifier),

    model_single_attribute: ($) => seq('@', $.attribute_specifier, optional($._model_attribute_args)),
    model_multi_attribute: ($) => seq('@@', $.attribute_specifier, optional($._model_attribute_args)),
    _model_attribute_args: ($) => seq('(', optional($._model_attribute_arg_separated), ')'),

    attribute_specifier: ($) => seq($.identifier, repeat(seq('.', $.identifier))),

    _model_attribute_arg_separated: ($) => seq($._model_attribute_arg, repeat(seq(',', $._model_attribute_arg))),
    _model_attribute_arg: ($) => choice($._model_attribute_arg_labeled, $._model_attribute_arg_no_label),
    _model_attribute_arg_labeled: ($) => seq(field('label', $.identifier), ':', $._model_attribute_arg_no_label),
    _model_attribute_arg_no_label: ($) => choice($._expression, $._field_array, $.identifier),

    _identifier_separated: ($) => seq($.identifier, repeat(seq(',', $.identifier))),

    field_type: ($) => choice($.nullable_type, $.non_null_type, $.array_type),
    nullable_type: ($) => seq($.non_null_type, '?'),
    array_type: ($) => seq($.non_null_type, '[', ']'),
    non_null_type: ($) => choice($.prisma_type, $.identifier),
    prisma_type: ($) => choice('String', 'Boolean', 'Int', 'DateTime', 'BigInt', 'Decimal', 'Float', 'Json', 'Bytes'),

    _field_array: ($) => seq('[', optional(field('fields', $._identifier_separated)), ']'),

    document_comment: ($) => token(seq('///', /.*/)),
    comment: ($) => token(seq('//', /(?:[^/].*)?/)),

    _expression: ($) =>
      choice(
        $.string,
        $._array,
        $.integer,
        $.boolean,
        $.apply_function,
        field('enum_value', $.identifier),
        $.special_constant,
      ),
    string: ($) => seq('"', repeat(choice(/[^"\\\n]/, $.string_char_escape)), '"'),
    integer: ($) => seq(optional('-'), /[1-9]\d*|0/),
    boolean: ($) => choice('true', 'false'),
    string_char_escape: ($) => choice('\\"', '\\\\', '\\n', '\\r'),
    apply_function: ($) => seq(field('name', $.identifier), '(', optional($._expression_separated), ')'),
    _expression_separated: ($) =>
      seq(field('argument', $._expression), repeat(seq(',', field('argument', $._expression)))),
    _array: ($) => choice(seq('[', optional($._expression_separated), ']')),
    special_constant: ($) => 'Max',

    identifier: ($) => /[a-zA-Z_][a-zA-Z0-9_]*/,
  },
});