%YAML 1.2 --- # https://react.dev/learn/writing-markup-with-jsx # JavaScript + JSX. Pure JS (no TypeScript types) with JSX tag support. name: JSX scope: source.jsx file_extensions: - jsx variables: identifier: '[A-Za-z_$][A-Za-z0-9_$]*' line_break: '(?:\x0D\x0A?|\x0A)' contexts: main: - include: whitespace - include: comments - include: decorator - include: jsx - include: strings - include: numbers - include: declaration-keywords - include: control-keywords - include: constants - include: function-calls - include: property-access - include: punctuation - include: identifiers whitespace: - match: '[\t ]+' comments: - match: '/\*' scope: punctuation.definition.comment.jsx push: - meta_scope: comment.block.jsx - match: '\*/' scope: punctuation.definition.comment.jsx pop: 1 - match: '//' scope: punctuation.definition.comment.jsx push: - meta_scope: comment.line.double-slash.jsx - match: '{{line_break}}' pop: 1 decorator: - match: '@{{identifier}}(?:\.{{identifier}})*' scope: entity.other.attribute-name.jsx strings: - match: '`' scope: punctuation.definition.string.begin.jsx push: - meta_scope: string.quoted.other.jsx - match: '\$\{' scope: punctuation.section.interpolation.begin.jsx push: - clear_scopes: 1 - meta_scope: meta.interpolation.jsx - include: main - match: '\}' scope: punctuation.section.interpolation.end.jsx pop: 1 - match: '\\[nrt`\\$]' scope: constant.character.escape.jsx - match: '`' scope: punctuation.definition.string.end.jsx pop: 1 - match: '"' scope: punctuation.definition.string.begin.jsx push: - meta_scope: string.quoted.double.jsx - match: '\\[nrt"\\]' scope: constant.character.escape.jsx - match: '"' scope: punctuation.definition.string.end.jsx pop: 1 - match: '{{line_break}}' scope: invalid.illegal.unclosed-string.jsx pop: 1 - match: "'" scope: punctuation.definition.string.begin.jsx push: - meta_scope: string.quoted.single.jsx - match: "\\\\[nrt'\\\\]" scope: constant.character.escape.jsx - match: "'" scope: punctuation.definition.string.end.jsx pop: 1 numbers: - match: '\b0[xX][0-9A-Fa-f_]+' scope: constant.numeric.integer.hexadecimal.jsx - match: '\b0[bB][01_]+' scope: constant.numeric.integer.binary.jsx - match: '\b0[oO][0-7_]+' scope: constant.numeric.integer.octal.jsx - match: '\b[0-9][0-9_]*(?:\.[0-9][0-9_]*)?(?:[eE][-+]?[0-9]+)?\b' scope: constant.numeric.decimal.jsx declaration-keywords: - match: '\b(?:var|let|const|function|class|import|export|from|as|default|extends|implements)\b' scope: keyword.declaration.jsx control-keywords: - match: '\b(?:if|else|for|while|do|switch|case|break|continue|return|throw|try|catch|finally|await|yield|new|delete|typeof|instanceof|in|of)\b' scope: keyword.control.jsx - match: '\b(?:async|await)\b' scope: keyword.control.async.jsx - match: '\b(?:true|false|null|undefined|this|super)\b' scope: constant.language.jsx constants: - match: '\b(?:console|Math|JSON|Object|Number|String|Boolean|Symbol|window|document|globalThis|process|React)\b' scope: support.class.jsx - match: '\b[A-Z][A-Z0-9_]+\b' scope: variable.other.constant.jsx function-calls: - match: '\b({{identifier}})\s*(?=\()' captures: 1: variable.function.jsx property-access: - match: '\.({{identifier}})\s*(?=\()' captures: 1: variable.function.jsx - match: '\.({{identifier}})\b' captures: 1: variable.other.property.jsx punctuation: - match: '[\(\)\{\}\[\];,]' scope: punctuation.jsx - match: '=>' scope: storage.type.function.arrow.jsx - match: '[-+*/%=<>!&|?~^]+' scope: keyword.operator.jsx identifiers: - match: '\b[A-Z][A-Za-z0-9_$]*\b' scope: entity.name.type.jsx - match: '{{identifier}}' scope: variable.jsx # ============ JSX 规则 ============ jsx: - match: '(<)((?:[A-Z][A-Za-z0-9_$]*|[a-z][A-Za-z0-9-]*))' captures: 1: punctuation.definition.tag.begin.jsx 2: entity.name.tag.jsx push: - meta_scope: meta.tag.jsx - include: jsx-attributes - match: '/>' scope: punctuation.definition.tag.end.jsx pop: 1 - match: '>' scope: punctuation.definition.tag.end.jsx pop: jsx-body - match: '()' scope: meta.tag.jsx captures: 1: punctuation.definition.tag.begin.jsx 2: entity.name.tag.jsx 3: punctuation.definition.tag.end.jsx - match: '(<)(>)' captures: 1: punctuation.definition.tag.begin.jsx 2: punctuation.definition.tag.end.jsx push: jsx-body jsx-attributes: - match: '\b([A-Za-z_][A-Za-z0-9_-]*)\s*(=)' captures: 1: entity.other.attribute-name.jsx 2: keyword.operator.assignment.jsx push: - match: '"' scope: punctuation.definition.string.begin.jsx push: - meta_scope: string.quoted.double.jsx - match: '"' scope: punctuation.definition.string.end.jsx pop: 1 - match: "'" scope: punctuation.definition.string.begin.jsx push: - meta_scope: string.quoted.single.jsx - match: "'" scope: punctuation.definition.string.end.jsx pop: 1 - match: '\{' scope: punctuation.section.embedded.begin.jsx push: - clear_scopes: 1 - meta_scope: meta.embedded.expression.jsx - include: main - match: '\}' scope: punctuation.section.embedded.end.jsx pop: 1 - match: '(?=\S)' pop: 1 - include: whitespace - match: '\b[A-Za-z_][A-Za-z0-9_-]*\b' scope: entity.other.attribute-name.jsx jsx-body: - meta_include_prototype: false - match: '(?=