tree-sitter-dockerfile/grammar.js

365 lines
7.8 KiB
JavaScript
Raw Normal View History

2021-05-09 22:11:30 -04:00
module.exports = grammar({
name: 'dockerfile',
2021-05-11 10:19:44 -04:00
extras: $ => [
$.comment,
/\s+/,
'\\\n'
],
2021-05-09 22:11:30 -04:00
rules: {
source_file: $ => repeat(seq($._instruction, "\n")),
_instruction: $ => choice(
$.from_instruction,
$.run_instruction,
$.cmd_instruction,
$.label_instruction,
$.expose_instruction,
$.env_instruction,
$.add_instruction,
$.copy_instruction,
$.entrypoint_instruction,
$.volume_instruction,
$.user_instruction,
$.workdir_instruction,
$.arg_instruction,
$.onbuild_instruction,
$.stopsignal_instruction,
$.healthcheck_instruction,
$.shell_instruction,
2021-05-10 23:16:32 -04:00
$.maintainer_instruction,
$.cross_build_instruction,
2021-05-09 22:11:30 -04:00
),
from_instruction: $ => seq(
alias(/[fF][rR][oO][mM]/, "FROM"),
$._non_newline_whitespace,
optional($.param),
$.image_spec,
optional(seq(
alias(/[aA][sS]/, "AS"),
2021-05-10 19:17:50 -04:00
field("as", $.image_alias),
2021-05-09 22:11:30 -04:00
)),
),
run_instruction: $ => seq(
alias(/[rR][uU][nN]/, "RUN"),
$._non_newline_whitespace,
choice(
$.string_array,
$.shell_command,
),
),
cmd_instruction: $ => seq(
alias(/[cC][mM][dD]/, "CMD"),
$._non_newline_whitespace,
choice(
$.string_array,
$.shell_command,
),
),
label_instruction: $ => seq(
alias(/[lL][aA][bB][eE][lL]/, "LABEL"),
$._non_newline_whitespace,
repeat1($.label_pair),
),
expose_instruction: $ => seq(
alias(/[eE][xX][pP][oO][sS][eE]/, "EXPOSE"),
2021-05-11 10:19:44 -04:00
repeat1(choice($.expose_port, $.expansion)),
2021-05-09 22:11:30 -04:00
),
env_instruction: $ => seq(
alias(/[eE][nN][vV]/, "ENV"),
$._non_newline_whitespace,
choice(
repeat1($.env_pair),
alias($._spaced_env_pair, $.env_pair),
)
2021-05-09 22:11:30 -04:00
),
add_instruction: $ => seq(
alias(/[aA][dD][dD]/, "ADD"),
$._non_newline_whitespace,
optional($.param),
$.path,
2021-05-10 17:11:30 -04:00
$._non_newline_whitespace,
2021-05-09 22:11:30 -04:00
$.path,
),
copy_instruction: $ => seq(
alias(/[cC][oO][pP][yY]/, "COPY"),
$._non_newline_whitespace,
optional($.param),
$.path,
2021-05-10 17:11:30 -04:00
$._non_newline_whitespace,
2021-05-09 22:11:30 -04:00
$.path,
),
entrypoint_instruction: $ => seq(
alias(/[eE][nN][tT][rR][yY][pP][oO][iI][nN][tT]/, "ENTRYPOINT"),
$._non_newline_whitespace,
choice(
$.string_array,
$.shell_command,
),
),
volume_instruction: $ => seq(
alias(/[vV][oO][lL][uU][mM][eE]/, "VOLUME"),
$._non_newline_whitespace,
choice(
$.string_array,
2021-05-10 17:11:30 -04:00
seq(
$.path,
repeat(seq($._non_newline_whitespace, $.path)),
),
2021-05-09 22:11:30 -04:00
),
),
user_instruction: $ => seq(
alias(/[uU][sS][eE][rR]/, "USER"),
$._non_newline_whitespace,
2021-05-10 17:11:30 -04:00
field("user", alias($._user_name_group, $.unquoted_string)),
2021-05-09 22:11:30 -04:00
optional(seq(
token.immediate(":"),
2021-05-10 17:11:30 -04:00
field("group", alias($._user_name_group, $.unquoted_string)),
2021-05-09 22:11:30 -04:00
)),
),
2021-05-10 17:11:30 -04:00
_user_name_group: $ => repeat1(choice(
token.immediate(/[a-z][-a-z0-9_]*/),
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-10 17:11:30 -04:00
)),
2021-05-09 22:11:30 -04:00
workdir_instruction: $ => seq(
alias(/[wW][oO][rR][kK][dD][iI][rR]/, "WORKDIR"),
$._non_newline_whitespace,
$.path,
),
arg_instruction: $ => seq(
alias(/[aA][rR][gG]/, "ARG"),
$._non_newline_whitespace,
field("name", alias(/[a-zA-Z0-9_]+/, $.unquoted_string)),
optional(seq(
token.immediate("="),
field("default", choice(
$.double_quoted_string,
$.unquoted_string,
)),
)),
),
onbuild_instruction: $ => seq(
alias(/[oO][nN][bB][uU][iI][lL][dD]/, "ONBUILD"),
$._non_newline_whitespace,
$._instruction,
),
stopsignal_instruction: $ => seq(
alias(/[sS][tT][oO][pP][sS][iI][gG][nN][aA][lL]/, "STOPSIGNAL"),
$._non_newline_whitespace,
2021-05-10 17:11:30 -04:00
$._stopsignal_value,
2021-05-09 22:11:30 -04:00
),
2021-05-10 17:11:30 -04:00
_stopsignal_value: $ => repeat1(choice(
/[A-Z0-9]+/,
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-10 17:11:30 -04:00
)),
2021-05-09 22:11:30 -04:00
healthcheck_instruction: $ => seq(
alias(/[hH][eE][aA][lL][tT][hH][cC][hH][eE][cC][kK]/, "HEALTHCHECK"),
$._non_newline_whitespace,
choice(
"NONE",
seq(
repeat($.param),
$.cmd_instruction,
),
),
),
shell_instruction: $ => seq(
alias(/[sS][hH][eE][lL][lL]/, "SHELL"),
$._non_newline_whitespace,
$.string_array,
),
2021-05-10 23:16:32 -04:00
maintainer_instruction: $ => seq(
alias(/[mM][aA][iI][nN][tT][aA][iI][nN][eE][rR]/, "MAINTAINER"),
/.*/,
),
cross_build_instruction: $ => seq(
alias(/[cC][rR][oO][sS][sS]_[bB][uU][iI][lL][dD][a-zA-Z_]*/, "CROSS_BUILD"),
/.*/,
),
2021-05-09 22:11:30 -04:00
2021-05-10 17:11:30 -04:00
path: $ => seq(
choice(
2021-05-11 10:19:44 -04:00
/[^-\s\$]/, // cannot start with a '-' to avoid conflicts with params
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-10 17:11:30 -04:00
),
repeat(choice(
2021-05-11 10:19:44 -04:00
/[^\s\$]+/,
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-10 17:11:30 -04:00
)),
),
2021-05-10 19:22:52 -04:00
expansion: $ => seq(
2021-05-11 10:19:44 -04:00
'$',
2021-05-10 19:35:00 -04:00
choice(
$.variable,
seq('{', alias(/[^\}]+/, $.variable), '}'),
)
2021-05-10 17:11:30 -04:00
),
2021-05-11 10:19:44 -04:00
variable: $ => /[a-zA-Z][a-zA-Z0-9_]*/,
2021-05-09 22:11:30 -04:00
env_pair: $ => seq(
2021-05-11 10:19:44 -04:00
field("name", $._env_key),
2021-05-09 22:11:30 -04:00
token.immediate("="),
field("value", choice(
$.double_quoted_string,
$.unquoted_string,
)),
),
_spaced_env_pair: $ => seq(
2021-05-11 10:19:44 -04:00
field("name", $._env_key),
token.immediate(/\s+/),
field("value", choice(
$.double_quoted_string,
$.unquoted_string,
)),
),
2021-05-11 10:19:44 -04:00
_env_key: $ => alias(/[a-zA-Z][a-zA-Z0-9_]*[a-zA-Z0-9]/, $.unquoted_string),
expose_port: $ => seq(
/\d+/,
optional(choice(
"/tcp",
"/udp",
)),
2021-05-09 22:11:30 -04:00
),
label_pair: $ => seq(
field("key", alias(/[-a-zA-Z0-9\._]+/, $.unquoted_string)),
token.immediate("="),
field("value", choice(
$.double_quoted_string,
$.unquoted_string,
)),
),
image_spec: $ => seq(
2021-05-10 17:11:30 -04:00
field("name", $.image_name),
2021-05-09 22:11:30 -04:00
seq(
2021-05-10 17:11:30 -04:00
field("tag", optional($.image_tag)),
field("digest", optional($.image_digest)),
2021-05-09 22:11:30 -04:00
),
),
2021-05-10 17:11:30 -04:00
image_name: $ => repeat1(choice(
2021-05-10 19:17:50 -04:00
token.immediate(/[^@:\s\$]+/),
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-09 22:11:30 -04:00
)),
2021-05-10 17:11:30 -04:00
image_tag: $ => seq(
token.immediate(":"),
repeat1(choice(
2021-05-10 19:17:50 -04:00
token.immediate(/[^@\s\$]+/),
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-10 17:11:30 -04:00
))
),
image_digest: $ => seq(
token.immediate("@"),
repeat1(choice(
2021-05-10 19:17:50 -04:00
token.immediate(/[a-zA-Z0-9:]+/),
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-10 17:11:30 -04:00
)),
),
2021-05-09 22:11:30 -04:00
param: $ => seq(
"--",
2021-05-10 17:11:30 -04:00
field("name", token.immediate(/[a-z][-a-z]*/)),
token.immediate("="),
field("value", token.immediate(/[^\s]+/)),
2021-05-09 22:11:30 -04:00
),
2021-05-10 19:17:50 -04:00
image_alias: $ => repeat1(choice(
/[-a-zA-Z0-9_]+/,
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-10 17:11:30 -04:00
)),
2021-05-09 22:11:30 -04:00
string_array: $ => seq(
"[",
optional(seq(
$.double_quoted_string,
repeat(seq(",", $.double_quoted_string)),
)),
"]",
),
shell_command: $ => seq(
$.shell_fragment,
repeat(seq(
$.line_continuation,
repeat($._comment_line),
$.shell_fragment,
)),
2021-05-09 22:11:30 -04:00
),
shell_fragment: $ => repeat1(choice(
/[^\\\[\n#\s][^\\\n]*/,
2021-05-10 23:04:55 -04:00
/\\[^\n]/,
)),
line_continuation: $ => '\\\n',
_comment_line: $ => seq(
alias($._anon_comment, $.comment), '\n'
),
_anon_comment: $ => seq('#', /.*/),
2021-05-09 22:11:30 -04:00
double_quoted_string: $ => seq(
'"',
repeat(choice(
2021-05-10 17:11:30 -04:00
token.immediate(prec(1, /[^"\n\\\$]+/)),
$.escape_sequence,
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-09 22:11:30 -04:00
)),
'"'
),
unquoted_string: $ => repeat1(choice(
2021-05-10 17:11:30 -04:00
token.immediate(/[^\s\n\"\\\$]+/),
2021-05-09 22:11:30 -04:00
token.immediate("\\ "),
2021-05-10 19:22:52 -04:00
$.expansion,
2021-05-09 22:11:30 -04:00
)),
escape_sequence: $ => token.immediate(seq(
'\\',
choice(
/[^xuU]/,
/\d{2,3}/,
/x[0-9a-fA-F]{2,}/,
/u[0-9a-fA-F]{4}/,
/U[0-9a-fA-F]{8}/
)
)),
2021-05-10 17:11:30 -04:00
_non_newline_whitespace: $ => /[\t ]+/,
2021-05-09 22:11:30 -04:00
comment: $ => seq("#", /.*/),
}
});