├── script ├── known_failures.txt └── parse-examples ├── .npmignore ├── .gitignore ├── queries ├── folds.scm ├── indents.scm ├── highlights.scm └── injections.scm ├── jsconfig.json ├── .gitattributes ├── bindings ├── node │ ├── index.js │ └── binding.cc └── rust │ ├── build.rs │ └── lib.rs ├── binding.gyp ├── Cargo.toml ├── .eslintrc.js ├── package.json ├── README.md ├── LICENSE ├── src ├── tree_sitter │ ├── alloc.h │ ├── parser.h │ └── array.h ├── tag.h ├── node-types.json ├── scanner.c └── grammar.json ├── Cargo.lock ├── grammar.js └── test └── corpus └── spec.txt /script/known_failures.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /test 2 | /examples 3 | /build 4 | /script 5 | /target 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | node_modules 3 | build 4 | package-lock.json 5 | /target/ 6 | .build/ -------------------------------------------------------------------------------- /queries/folds.scm: -------------------------------------------------------------------------------- 1 | [ 2 | (element) 3 | (template_element) 4 | (script_element) 5 | (style_element) 6 | ] @fold 7 | -------------------------------------------------------------------------------- /queries/indents.scm: -------------------------------------------------------------------------------- 1 | ; inherits: html_tags 2 | (template_element) @indent.begin 3 | 4 | (template_element 5 | (end_tag 6 | ">" @indent.end) @indent.branch) 7 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": ["grammar.js"], 3 | "exclude": ["node_modules"], 4 | "compilerOptions": { 5 | "checkJs": true, 6 | "module": "Node16", 7 | "types": ["tree-sitter-cli/dsl"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /src/** linguist-vendored 2 | /examples/* linguist-vendored 3 | 4 | src/grammar.json linguist-generated 5 | src/node-types.json linguist-generated 6 | src/parser.c linguist-generated 7 | 8 | src/grammar.json -diff 9 | src/node-types.json -diff 10 | src/parser.c -diff 11 | -------------------------------------------------------------------------------- /bindings/node/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | module.exports = require('../../build/Release/tree_sitter_vue_binding'); 3 | } catch (error1) { 4 | if (error1.code !== 'MODULE_NOT_FOUND') { 5 | throw error1; 6 | } 7 | try { 8 | module.exports = require('../../build/Debug/tree_sitter_vue_binding'); 9 | } catch (error2) { 10 | if (error2.code !== 'MODULE_NOT_FOUND') { 11 | throw error2; 12 | } 13 | throw error1 14 | } 15 | } 16 | 17 | try { 18 | module.exports.nodeTypeInfo = require('../../src/node-types.json'); 19 | } catch (_) {} 20 | -------------------------------------------------------------------------------- /queries/highlights.scm: -------------------------------------------------------------------------------- 1 | ; inherits: html_tags 2 | [ 3 | (dynamic_directive_inner_value) 4 | ] @tag 5 | 6 | [ 7 | "[" 8 | "]" 9 | ] @punctuation.bracket 10 | 11 | (interpolation) @punctuation.special 12 | 13 | (interpolation 14 | (raw_text) @none) 15 | 16 | (directive_name) @tag.attribute 17 | 18 | (directive_attribute 19 | (quoted_attribute_value) @punctuation.special) 20 | 21 | (directive_attribute 22 | (quoted_attribute_value 23 | (attribute_value) @none)) 24 | 25 | [ 26 | (directive_modifier) 27 | (directive_value) 28 | ] @function.method 29 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_vue_binding", 5 | "include_dirs": [ 6 | ""] 9 | edition = "2021" 10 | license = "MIT" 11 | 12 | build = "bindings/rust/build.rs" 13 | include = [ 14 | "bindings/rust/*", 15 | "grammar.js", 16 | "queries/*", 17 | "src/*" 18 | ] 19 | 20 | [lib] 21 | path = "bindings/rust/lib.rs" 22 | 23 | [dependencies] 24 | tree-sitter = "~0.20.10" 25 | 26 | [build-dependencies] 27 | cc = "^1.0" 28 | -------------------------------------------------------------------------------- /bindings/rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let src_dir = std::path::Path::new("src"); 3 | 4 | let mut c_config = cc::Build::new(); 5 | c_config.include(src_dir); 6 | c_config 7 | .flag_if_supported("-Wno-unused-parameter") 8 | .flag_if_supported("-Wno-unused-but-set-variable"); 9 | let parser_path = src_dir.join("parser.c"); 10 | c_config.file(&parser_path); 11 | 12 | // NOTE: uncomment this block if your language uses an external scanner: 13 | /* 14 | let scanner_path = src_dir.join("scanner.c"); 15 | c_config.file(&scanner_path); 16 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 17 | */ 18 | 19 | c_config.compile("parser"); 20 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 21 | } 22 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'env': { 3 | 'commonjs': true, 4 | 'es2021': true, 5 | 'node': true, 6 | }, 7 | 'extends': 'google', 8 | 'overrides': [ 9 | { 10 | 'env': { 11 | 'node': true, 12 | }, 13 | 'files': [ 14 | '.eslintrc.{js,cjs}', 15 | ], 16 | 'parserOptions': { 17 | 'sourceType': 'script', 18 | }, 19 | }, 20 | ], 21 | 'parserOptions': { 22 | 'ecmaVersion': 'latest', 23 | 'sourceType': 'module', 24 | }, 25 | 'rules': { 26 | 'indent': ['error', 2, {'SwitchCase': 1}], 27 | 'max-len': [ 28 | 'error', 29 | {'code': 120, 'ignoreComments': true, 'ignoreUrls': true, 'ignoreStrings': true}, 30 | ], 31 | 'arrow-parens': 'off', 32 | 'camelcase': 'off', 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-vue", 3 | "version": "0.1.0", 4 | "license": "MIT", 5 | "description": "vue grammar for tree-sitter", 6 | "repository": "tree-sitter-grammars/tree-sitter-vue", 7 | "author": "Amaan Qureshi ", 8 | "keywords": [ 9 | "tree-sitter", 10 | "parser", 11 | "lexer", 12 | "vue" 13 | ], 14 | "scripts": { 15 | "build": "tree-sitter generate", 16 | "parse": "tree-sitter parse", 17 | "test": "tree-sitter test", 18 | "wasm": "tree-sitter build-wasm", 19 | "web": "tree-sitter web-ui" 20 | }, 21 | "main": "bindings/node", 22 | "dependencies": { 23 | "nan": "^2.18.0", 24 | "tree-sitter-html": "^0.20.1" 25 | }, 26 | "devDependencies": { 27 | "eslint": ">=5.16.0", 28 | "eslint-config-google": "^0.14.0", 29 | "tree-sitter-cli": "~0.21.0-pre-release-1" 30 | }, 31 | "tree-sitter": [ 32 | { 33 | "scope": "source.vue" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /bindings/node/binding.cc: -------------------------------------------------------------------------------- 1 | #include "nan.h" 2 | #include "tree_sitter/parser.h" 3 | #include 4 | 5 | using namespace v8; 6 | 7 | extern "C" TSLanguage * tree_sitter_vue(); 8 | 9 | namespace { 10 | 11 | NAN_METHOD(New) {} 12 | 13 | void Init(Local exports, Local module) { 14 | Local tpl = Nan::New(New); 15 | tpl->SetClassName(Nan::New("Language").ToLocalChecked()); 16 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 17 | 18 | Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); 19 | Local instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); 20 | Nan::SetInternalFieldPointer(instance, 0, tree_sitter_vue()); 21 | 22 | Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("vue").ToLocalChecked()); 23 | Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); 24 | } 25 | 26 | NODE_MODULE(tree_sitter_vue_binding, Init) 27 | 28 | } // namespace 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-vue 2 | 3 | [![CI][ci]](https://github.com/tree-sitter-grammars/tree-sitter-vue/actions/workflows/ci.yml) 4 | [![discord][discord]](https://discord.gg/w7nTvsVJhm) 5 | [![matrix][matrix]](https://matrix.to/#/#tree-sitter-chat:matrix.org) 6 | 7 | 8 | 9 | 10 | A tree-sitter parser for vue files. 11 | 12 | ## References 13 | 14 | 15 | 16 | [ci]: https://img.shields.io/github/actions/workflow/status/tree-sitter-grammars/tree-sitter-vue/ci.yml?logo=github&label=CI 17 | [discord]: https://img.shields.io/discord/1063097320771698699?logo=discord&label=discord 18 | [matrix]: https://img.shields.io/matrix/tree-sitter-chat%3Amatrix.org?logo=matrix&label=matrix 19 | [npm]: https://img.shields.io/npm/v/tree-sitter-vue?logo=npm 20 | [crates]: https://img.shields.io/crates/v/tree-sitter-vue?logo=rust 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Amaan Qureshi 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/tree_sitter/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ALLOC_H_ 2 | #define TREE_SITTER_ALLOC_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Allow clients to override allocation functions 13 | #ifdef TREE_SITTER_REUSE_ALLOCATOR 14 | 15 | extern void *(*ts_current_malloc)(size_t); 16 | extern void *(*ts_current_calloc)(size_t, size_t); 17 | extern void *(*ts_current_realloc)(void *, size_t); 18 | extern void (*ts_current_free)(void *); 19 | 20 | #ifndef ts_malloc 21 | #define ts_malloc ts_current_malloc 22 | #endif 23 | #ifndef ts_calloc 24 | #define ts_calloc ts_current_calloc 25 | #endif 26 | #ifndef ts_realloc 27 | #define ts_realloc ts_current_realloc 28 | #endif 29 | #ifndef ts_free 30 | #define ts_free ts_current_free 31 | #endif 32 | 33 | #else 34 | 35 | #ifndef ts_malloc 36 | #define ts_malloc malloc 37 | #endif 38 | #ifndef ts_calloc 39 | #define ts_calloc calloc 40 | #endif 41 | #ifndef ts_realloc 42 | #define ts_realloc realloc 43 | #endif 44 | #ifndef ts_free 45 | #define ts_free free 46 | #endif 47 | 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif // TREE_SITTER_ALLOC_H_ 55 | -------------------------------------------------------------------------------- /script/parse-examples: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | function clone_repo { 8 | owner=$1 9 | name=$2 10 | sha=$3 11 | 12 | path=examples/$name 13 | if [ ! -d "$path" ]; then 14 | echo "Cloning $owner/$name" 15 | git clone "https://github.com/$owner/$name" "$path" 16 | fi 17 | 18 | pushd "$path" >/dev/null 19 | actual_sha=$(git rev-parse HEAD) 20 | if [ "$actual_sha" != "$sha" ]; then 21 | echo "Updating $owner/$name to $sha" 22 | git fetch 23 | git reset --hard "$sha" 24 | fi 25 | popd >/dev/null 26 | } 27 | 28 | clone_repo vuejs core ca9920c7d708c9da48ef0bd116610f1ecb6b56a9 29 | clone_repo vuetifyjs vuetify 136dd51e5cceed9699cbd3b752bb4b5fc03164b6 30 | clone_repo element-plus element-plus 48a056b051c8d571657900aae02ec8cbeff83077 31 | 32 | known_failures=$(cat script/known_failures.txt) 33 | 34 | # shellcheck disable=2046 35 | tree-sitter parse -q -s \ 36 | 'examples/**/*.vue' \ 37 | $(for file in $known_failures; do echo "!${file}"; done) 38 | 39 | example_count=$(find examples -name '*.vue' | wc -l) 40 | failure_count=$(wc -w <<<"$known_failures") 41 | success_count=$((example_count - failure_count)) 42 | success_percent=$(bc -l <<<"100*${success_count}/${example_count}") 43 | 44 | printf \ 45 | "Successfully parsed %d of %d example files (%.1f%%)\n" \ 46 | "$success_count" "$example_count" "$success_percent" 47 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides vue language support for the [tree-sitter][] parsing library. 2 | //! 3 | //! Typically, you will use the [language][language func] function to add this language to a 4 | //! tree-sitter [Parser][], and then use the parser to parse some code: 5 | //! 6 | //! ``` 7 | //! let code = r#" 8 | //! "#; 9 | //! let mut parser = tree_sitter::Parser::new(); 10 | //! parser.set_language(tree_sitter_vue::language()).expect("Error loading vue grammar"); 11 | //! let tree = parser.parse(code, None).unwrap(); 12 | //! assert!(!tree.root_node().has_error()); 13 | //! ``` 14 | //! 15 | //! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 16 | //! [language func]: fn.language.html 17 | //! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html 18 | //! [tree-sitter]: https://tree-sitter.github.io/ 19 | 20 | use tree_sitter::Language; 21 | 22 | extern "C" { 23 | fn tree_sitter_vue() -> Language; 24 | } 25 | 26 | /// Get the tree-sitter [Language][] for this grammar. 27 | /// 28 | /// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 29 | pub fn language() -> Language { 30 | unsafe { tree_sitter_vue() } 31 | } 32 | 33 | /// The content of the [`node-types.json`][] file for this grammar. 34 | /// 35 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types 36 | pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); 37 | 38 | // NOTE: uncomment these to include any queries that this grammar contains: 39 | // pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); 40 | // pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); 41 | // pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); 42 | // pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); 43 | 44 | 45 | #[cfg(test)] 46 | mod tests { 47 | #[test] 48 | fn test_can_load_grammar() { 49 | let mut parser = tree_sitter::Parser::new(); 50 | parser 51 | .set_language(super::language()) 52 | .expect("Error loading vue language"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /queries/injections.scm: -------------------------------------------------------------------------------- 1 | ; inherits html_tags 2 | ;