Add @if/@for support in JSON/JS/CSS embedded blocks
This commit is contained in:
parent
b6a168a2b6
commit
7c37d0b3bc
228
grammar.js
228
grammar.js
|
|
@ -223,7 +223,7 @@ module.exports = grammar({
|
|||
),
|
||||
|
||||
expression_path: ($) =>
|
||||
seq(
|
||||
prec.left(seq(
|
||||
$.identifier,
|
||||
repeat(
|
||||
choice(
|
||||
|
|
@ -232,7 +232,7 @@ module.exports = grammar({
|
|||
seq("(", optional($.argument_list), ")"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
|
||||
// Control flow
|
||||
template_control_flow: ($) =>
|
||||
|
|
@ -590,13 +590,233 @@ module.exports = grammar({
|
|||
|
||||
// Embedded language blocks: @```lang ... ```@
|
||||
embedded_language: ($) =>
|
||||
seq("@```", $.language_name, optional($.embedded_content), "```@"),
|
||||
choice(
|
||||
// JSON/Alpine blocks with structured parsing
|
||||
seq("@```", choice("json", "alpine"), optional($.json_content), "```@"),
|
||||
// JS blocks with structured parsing
|
||||
seq("@```", choice("js", "javascript"), optional($.js_content), "```@"),
|
||||
// CSS blocks with structured parsing
|
||||
seq("@```", choice("css", "style"), optional($.css_content), "```@"),
|
||||
// HTML blocks (less common, use simple content)
|
||||
seq("@```", "html", optional($.embedded_content_simple), "```@"),
|
||||
),
|
||||
|
||||
embedded_content: ($) => /([^`]|`[^`]|``[^`])*/,
|
||||
// Simple embedded content fallback
|
||||
embedded_content_simple: ($) => /([^`]|`[^`]|``[^`])*/,
|
||||
|
||||
language_name: ($) =>
|
||||
choice("html", "css", "js", "javascript", "json", "alpine", "style"),
|
||||
|
||||
// JSON content with template support
|
||||
json_content: ($) =>
|
||||
choice(
|
||||
$.json_object,
|
||||
$.json_array,
|
||||
),
|
||||
|
||||
json_object: ($) =>
|
||||
seq(
|
||||
"{",
|
||||
optional($.json_object_content),
|
||||
"}",
|
||||
),
|
||||
|
||||
json_object_content: ($) =>
|
||||
seq(
|
||||
$.json_member_or_control,
|
||||
repeat(seq(optional(","), $.json_member_or_control)),
|
||||
optional(","),
|
||||
),
|
||||
|
||||
json_member_or_control: ($) =>
|
||||
choice(
|
||||
$.json_member,
|
||||
$.json_control_flow,
|
||||
),
|
||||
|
||||
json_member: ($) =>
|
||||
seq(
|
||||
choice($.json_key, $.template_expression),
|
||||
":",
|
||||
$.json_value,
|
||||
),
|
||||
|
||||
json_key: ($) =>
|
||||
choice(
|
||||
$.string_literal,
|
||||
$.identifier, // Allow unquoted keys for JS object shorthand
|
||||
),
|
||||
|
||||
json_value: ($) =>
|
||||
choice(
|
||||
$.json_object,
|
||||
$.json_array,
|
||||
$.string_literal,
|
||||
$.number_literal,
|
||||
$.boolean_literal,
|
||||
"null",
|
||||
$.template_expression,
|
||||
$.json_method, // For Alpine.js method shorthand
|
||||
),
|
||||
|
||||
json_array: ($) =>
|
||||
seq(
|
||||
"[",
|
||||
optional($.json_array_content),
|
||||
"]",
|
||||
),
|
||||
|
||||
json_array_content: ($) =>
|
||||
seq(
|
||||
$.json_array_element,
|
||||
repeat(seq(optional(","), $.json_array_element)),
|
||||
optional(","),
|
||||
),
|
||||
|
||||
json_array_element: ($) =>
|
||||
choice(
|
||||
$.json_value,
|
||||
$.json_control_flow,
|
||||
),
|
||||
|
||||
// Control flow in JSON context
|
||||
json_control_flow: ($) =>
|
||||
choice(
|
||||
$.json_if_statement,
|
||||
$.json_for_loop,
|
||||
),
|
||||
|
||||
json_if_statement: ($) =>
|
||||
seq(
|
||||
"@if",
|
||||
$.expression,
|
||||
"{",
|
||||
optional($.json_if_body),
|
||||
"}",
|
||||
optional(seq("else", "{", optional($.json_if_body), "}")),
|
||||
),
|
||||
|
||||
// Body of @if in JSON can contain members or array elements
|
||||
json_if_body: ($) =>
|
||||
seq(
|
||||
$.json_if_element,
|
||||
repeat(seq(optional(","), $.json_if_element)),
|
||||
optional(","),
|
||||
),
|
||||
|
||||
json_if_element: ($) =>
|
||||
choice(
|
||||
$.json_member,
|
||||
$.json_value,
|
||||
$.json_control_flow,
|
||||
),
|
||||
|
||||
json_for_loop: ($) =>
|
||||
seq(
|
||||
"@for",
|
||||
$.simple_pattern,
|
||||
"in",
|
||||
$.expression,
|
||||
"{",
|
||||
optional($.json_if_body),
|
||||
"}",
|
||||
),
|
||||
|
||||
// Alpine.js method shorthand: toggle() { this.open = !this.open; }
|
||||
json_method: ($) =>
|
||||
seq(
|
||||
$.identifier,
|
||||
"(",
|
||||
optional($.json_method_params),
|
||||
")",
|
||||
"{",
|
||||
optional($.js_content),
|
||||
"}",
|
||||
),
|
||||
|
||||
json_method_params: ($) =>
|
||||
seq($.identifier, repeat(seq(",", $.identifier))),
|
||||
|
||||
// JavaScript content with template support
|
||||
js_content: ($) => repeat1($.js_element),
|
||||
|
||||
js_element: ($) =>
|
||||
choice(
|
||||
$.js_control_flow,
|
||||
$.template_expression,
|
||||
$.js_code,
|
||||
),
|
||||
|
||||
js_control_flow: ($) =>
|
||||
choice(
|
||||
$.js_if_statement,
|
||||
$.js_for_loop,
|
||||
),
|
||||
|
||||
js_if_statement: ($) =>
|
||||
seq(
|
||||
"@if",
|
||||
$.expression,
|
||||
"{",
|
||||
optional($.js_content),
|
||||
"}",
|
||||
optional(seq("else", "{", optional($.js_content), "}")),
|
||||
),
|
||||
|
||||
js_for_loop: ($) =>
|
||||
seq(
|
||||
"@for",
|
||||
$.simple_pattern,
|
||||
"in",
|
||||
$.expression,
|
||||
"{",
|
||||
optional($.js_content),
|
||||
"}",
|
||||
),
|
||||
|
||||
// Raw JS code (anything that's not @expression or @control_flow)
|
||||
js_code: ($) => token(prec(-1, /[^@`]+/)),
|
||||
|
||||
// CSS content with template support
|
||||
css_content: ($) => repeat1($.css_element),
|
||||
|
||||
css_element: ($) =>
|
||||
choice(
|
||||
$.css_control_flow,
|
||||
$.template_expression,
|
||||
$.css_code,
|
||||
),
|
||||
|
||||
css_control_flow: ($) =>
|
||||
choice(
|
||||
$.css_if_statement,
|
||||
$.css_for_loop,
|
||||
),
|
||||
|
||||
css_if_statement: ($) =>
|
||||
seq(
|
||||
"@if",
|
||||
$.expression,
|
||||
"{",
|
||||
optional($.css_content),
|
||||
"}",
|
||||
optional(seq("else", "{", optional($.css_content), "}")),
|
||||
),
|
||||
|
||||
css_for_loop: ($) =>
|
||||
seq(
|
||||
"@for",
|
||||
$.simple_pattern,
|
||||
"in",
|
||||
$.expression,
|
||||
"{",
|
||||
optional($.css_content),
|
||||
"}",
|
||||
),
|
||||
|
||||
// Raw CSS code
|
||||
css_code: ($) => token(prec(-1, /[^@`]+/)),
|
||||
|
||||
// Escape sequence for literal @
|
||||
escape_at: ($) => "@@",
|
||||
|
||||
|
|
|
|||
|
|
@ -97,8 +97,14 @@
|
|||
(escape_sequence) @escape
|
||||
(escape_at) @escape
|
||||
|
||||
; Embedded
|
||||
(language_name) @label
|
||||
; Embedded language names
|
||||
"json" @label
|
||||
"alpine" @label
|
||||
"js" @label
|
||||
"javascript" @label
|
||||
"css" @label
|
||||
"style" @label
|
||||
"html" @label
|
||||
|
||||
; Variables (fallback)
|
||||
(identifier) @variable
|
||||
|
|
|
|||
1126
src/grammar.json
1126
src/grammar.json
File diff suppressed because it is too large
Load Diff
|
|
@ -399,6 +399,110 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "css_code",
|
||||
"named": true,
|
||||
"fields": {}
|
||||
},
|
||||
{
|
||||
"type": "css_content",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "css_element",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "css_control_flow",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "css_for_loop",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "css_if_statement",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "css_element",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "css_code",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "css_control_flow",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "template_expression",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "css_for_loop",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "css_content",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "simple_pattern",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "css_if_statement",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "css_content",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "default_value",
|
||||
"named": true,
|
||||
|
|
@ -457,15 +561,23 @@
|
|||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"multiple": false,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "embedded_content",
|
||||
"type": "css_content",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "language_name",
|
||||
"type": "embedded_content_simple",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "js_content",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_content",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
|
|
@ -902,10 +1014,444 @@
|
|||
"fields": {}
|
||||
},
|
||||
{
|
||||
"type": "language_name",
|
||||
"type": "js_code",
|
||||
"named": true,
|
||||
"fields": {}
|
||||
},
|
||||
{
|
||||
"type": "js_content",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "js_element",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "js_control_flow",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "js_for_loop",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "js_if_statement",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "js_element",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "js_code",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "js_control_flow",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "template_expression",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "js_for_loop",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "js_content",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "simple_pattern",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "js_if_statement",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "js_content",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_array",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_array_content",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_array_content",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_array_element",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_array_element",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_control_flow",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_value",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_content",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_array",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_object",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_control_flow",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_for_loop",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_if_statement",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_for_loop",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_if_body",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "simple_pattern",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_if_body",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_if_element",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_if_element",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_control_flow",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_member",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_value",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_if_statement",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_if_body",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_key",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "string_literal",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_member",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_key",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_value",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "template_expression",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_member_or_control",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_control_flow",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_member",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_method",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "js_content",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_method_params",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_method_params",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_object",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_object_content",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_object_content",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "json_member_or_control",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "json_value",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": false,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "boolean_literal",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_array",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_method",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "json_object",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "number_literal",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "string_literal",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "template_expression",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "let_statement",
|
||||
"named": true,
|
||||
|
|
@ -2013,7 +2559,7 @@
|
|||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "embedded_content",
|
||||
"type": "embedded_content_simple",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
|
|
@ -2104,6 +2650,10 @@
|
|||
"type": "mut",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "safe",
|
||||
"named": false
|
||||
|
|
|
|||
48898
src/parser.c
48898
src/parser.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue