chore: add eclint for editorconfig linting and fix violations

- Install eclint ^2.8.1 for editorconfig validation and fixing
- Add .eclintignore to exclude generated files and dependencies
- Add npm scripts: lint:editorconfig and lint:editorconfig:fix
- Fix indentation issues in CONTRIBUTING.md (3 spaces -> 2 spaces)
- Fix code alignment in scanner.c to match editorconfig rules
- Regenerate parser after scanner.c formatting changes
This commit is contained in:
2025-11-26 00:09:28 +02:00
parent 41b3c5d345
commit 8ad4483b0b
7 changed files with 3037 additions and 88 deletions

21
.eclintignore Normal file
View File

@@ -0,0 +1,21 @@
# Dependencies
node_modules/
# Generated files
src/parser.c
src/grammar.json
src/node-types.json
src/tree_sitter/
# Build artifacts
build/
dist/
# Logs
*.log
megalinter-reports/
# Lock files
package-lock.json
pnpm-lock.yaml
yarn.lock

View File

@@ -28,42 +28,42 @@ Thank you for your interest in contributing to tree-sitter-shellspec! This docum
1. Fork the repository on GitHub 1. Fork the repository on GitHub
2. Clone your fork locally: 2. Clone your fork locally:
```bash ```bash
git clone https://github.com/YOUR_USERNAME/tree-sitter-shellspec.git git clone https://github.com/YOUR_USERNAME/tree-sitter-shellspec.git
cd tree-sitter-shellspec cd tree-sitter-shellspec
``` ```
3. Add the upstream repository: 3. Add the upstream repository:
```bash ```bash
git remote add upstream https://github.com/ivuorinen/tree-sitter-shellspec.git git remote add upstream https://github.com/ivuorinen/tree-sitter-shellspec.git
``` ```
## Development Setup ## Development Setup
1. **Install dependencies:** 1. **Install dependencies:**
```bash ```bash
npm install npm install
``` ```
2. **Generate the grammar:** 2. **Generate the grammar:**
```bash ```bash
npm run generate npm run generate
``` ```
3. **Run tests:** 3. **Run tests:**
```bash ```bash
npm test npm test
``` ```
4. **Build the parser:** 4. **Build the parser:**
```bash ```bash
npm run build npm run build
``` ```
### Development Workflow ### Development Workflow
@@ -209,33 +209,33 @@ tree-sitter test --debug
1. **Create a feature branch:** 1. **Create a feature branch:**
```bash ```bash
git checkout -b feature/your-feature-name git checkout -b feature/your-feature-name
``` ```
2. **Make your changes** following the guidelines above 2. **Make your changes** following the guidelines above
3. **Commit with clear messages:** 3. **Commit with clear messages:**
```bash ```bash
git commit -m "feat: add support for Data block modifiers git commit -m "feat: add support for Data block modifiers
- Add :raw and :expand modifier support - Add :raw and :expand modifier support
- Update test cases for new syntax - Update test cases for new syntax
- Add documentation examples" - Add documentation examples"
``` ```
4. **Push to your fork:** 4. **Push to your fork:**
```bash ```bash
git push origin feature/your-feature-name git push origin feature/your-feature-name
``` ```
5. **Create a Pull Request** with: 5. **Create a Pull Request** with:
- Clear description of changes - Clear description of changes
- References to related issues - References to related issues
- Test results and coverage - Test results and coverage
- Breaking change notes (if any) - Breaking change notes (if any)
### Commit Message Guidelines ### Commit Message Guidelines
@@ -282,43 +282,43 @@ Use the [Grammar Issue template](.github/ISSUE_TEMPLATE/grammar_issue.md) for:
### High Priority ### High Priority
1. **Enhanced Data block support** 1. **Enhanced Data block support**
- `:raw` and `:expand` modifiers - `:raw` and `:expand` modifiers
- Pipe filter syntax (`Data | command`) - Pipe filter syntax (`Data | command`)
- Multi-line `#|` syntax - Multi-line `#|` syntax
2. **Assertion parsing** 2. **Assertion parsing**
- When/The statement structures - When/The statement structures
- Matcher syntax parsing - Matcher syntax parsing
- Subject/predicate analysis - Subject/predicate analysis
3. **Performance optimization** 3. **Performance optimization**
- Reduce parser conflicts - Reduce parser conflicts
- Optimize grammar rules - Optimize grammar rules
- Improve parsing speed - Improve parsing speed
### Medium Priority ### Medium Priority
1. **Editor integration** 1. **Editor integration**
- Neovim configuration examples - Neovim configuration examples
- VS Code extension support - VS Code extension support
- Emacs tree-sitter integration - Emacs tree-sitter integration
2. **Tooling improvements** 2. **Tooling improvements**
- Syntax highlighting themes - Syntax highlighting themes
- Language server features - Language server features
- Code formatting rules - Code formatting rules
3. **Documentation** 3. **Documentation**
- Usage tutorials - Usage tutorials
- Grammar development guide - Grammar development guide
- Editor setup instructions - Editor setup instructions
### Low Priority ### Low Priority
1. **Advanced features** 1. **Advanced features**
- ShellSpec custom matchers - ShellSpec custom matchers
- Configuration file parsing - Configuration file parsing
- Metadata extraction - Metadata extraction
## Development Resources ## Development Resources

2926
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,8 @@
"lint": "npx mega-linter-runner", "lint": "npx mega-linter-runner",
"lint:yaml": "yamllint .", "lint:yaml": "yamllint .",
"lint:markdown": "markdownlint . --config .markdownlint.json --ignore node_modules --fix", "lint:markdown": "markdownlint . --config .markdownlint.json --ignore node_modules --fix",
"lint:editorconfig": "eclint check .",
"lint:editorconfig:fix": "eclint fix .",
"format": "prettier --write .", "format": "prettier --write .",
"format:check": "prettier --check .", "format:check": "prettier --check .",
"precommit": "pre-commit run --all-files", "precommit": "pre-commit run --all-files",
@@ -37,6 +39,7 @@
"tree-sitter-bash": "^0.25.0" "tree-sitter-bash": "^0.25.0"
}, },
"devDependencies": { "devDependencies": {
"eclint": "^2.8.1",
"markdownlint-cli": "^0.46.0", "markdownlint-cli": "^0.46.0",
"nodemon": "^3.0.1", "nodemon": "^3.0.1",
"prettier": "^3.6.2", "prettier": "^3.6.2",

View File

@@ -1,4 +1,4 @@
/* Automatically @generated by tree-sitter v0.25.9 */ /* Automatically @generated by tree-sitter v0.25.10 */
#include "tree_sitter/parser.h" #include "tree_sitter/parser.h"

View File

@@ -116,7 +116,7 @@ static unsigned serialize(Scanner *scanner, char *buffer) {
size += sizeof(uint32_t); size += sizeof(uint32_t);
if (heredoc->delimiter.size > 0) { if (heredoc->delimiter.size > 0) {
memcpy(&buffer[size], heredoc->delimiter.contents, memcpy(&buffer[size], heredoc->delimiter.contents,
heredoc->delimiter.size); heredoc->delimiter.size);
size += heredoc->delimiter.size; size += heredoc->delimiter.size;
} }
} }
@@ -159,7 +159,7 @@ static void deserialize(Scanner *scanner, const char *buffer, unsigned length) {
if (heredoc->delimiter.size > 0) { if (heredoc->delimiter.size > 0) {
memcpy(heredoc->delimiter.contents, &buffer[size], memcpy(heredoc->delimiter.contents, &buffer[size],
heredoc->delimiter.size); heredoc->delimiter.size);
size += heredoc->delimiter.size; size += heredoc->delimiter.size;
// Ensure NUL termination for safety // Ensure NUL termination for safety
if (heredoc->delimiter.contents[heredoc->delimiter.size - 1] != '\0') { if (heredoc->delimiter.contents[heredoc->delimiter.size - 1] != '\0') {
@@ -190,9 +190,9 @@ static bool advance_word(TSLexer *lexer, String *unquoted_word) {
} }
while (lexer->lookahead && while (lexer->lookahead &&
!(quote ? lexer->lookahead == quote || lexer->lookahead == '\r' || !(quote ? lexer->lookahead == quote || lexer->lookahead == '\r' ||
lexer->lookahead == '\n' lexer->lookahead == '\n'
: iswspace(lexer->lookahead))) { : iswspace(lexer->lookahead))) {
if (lexer->lookahead == '\\') { if (lexer->lookahead == '\\') {
advance(lexer); advance(lexer);
if (!lexer->lookahead) { if (!lexer->lookahead) {
@@ -214,7 +214,7 @@ static bool advance_word(TSLexer *lexer, String *unquoted_word) {
static inline bool scan_bare_dollar(TSLexer *lexer) { static inline bool scan_bare_dollar(TSLexer *lexer) {
while (iswspace(lexer->lookahead) && lexer->lookahead != '\n' && while (iswspace(lexer->lookahead) && lexer->lookahead != '\n' &&
!lexer->eof(lexer)) { !lexer->eof(lexer)) {
skip(lexer); skip(lexer);
} }
@@ -223,7 +223,7 @@ static inline bool scan_bare_dollar(TSLexer *lexer) {
lexer->result_symbol = BARE_DOLLAR; lexer->result_symbol = BARE_DOLLAR;
lexer->mark_end(lexer); lexer->mark_end(lexer);
return iswspace(lexer->lookahead) || lexer->eof(lexer) || return iswspace(lexer->lookahead) || lexer->eof(lexer) ||
lexer->lookahead == '\"'; lexer->lookahead == '\"';
} }
return false; return false;
@@ -253,8 +253,8 @@ static bool scan_heredoc_end_identifier(Heredoc *heredoc, TSLexer *lexer) {
int32_t size = 0; int32_t size = 0;
if (heredoc->delimiter.size > 0) { if (heredoc->delimiter.size > 0) {
while (lexer->lookahead != '\0' && lexer->lookahead != '\n' && while (lexer->lookahead != '\0' && lexer->lookahead != '\n' &&
(int32_t)*array_get(&heredoc->delimiter, size) == lexer->lookahead && (int32_t)*array_get(&heredoc->delimiter, size) == lexer->lookahead &&
heredoc->current_leading_word.size < heredoc->delimiter.size) { heredoc->current_leading_word.size < heredoc->delimiter.size) {
array_push(&heredoc->current_leading_word, lexer->lookahead); array_push(&heredoc->current_leading_word, lexer->lookahead);
advance(lexer); advance(lexer);
size++; size++;
@@ -262,14 +262,14 @@ static bool scan_heredoc_end_identifier(Heredoc *heredoc, TSLexer *lexer) {
} }
array_push(&heredoc->current_leading_word, '\0'); array_push(&heredoc->current_leading_word, '\0');
return heredoc->delimiter.size == 0 return heredoc->delimiter.size == 0
? false ? false
: strcmp(heredoc->current_leading_word.contents, : strcmp(heredoc->current_leading_word.contents,
heredoc->delimiter.contents) == 0; heredoc->delimiter.contents) == 0;
} }
static bool scan_heredoc_content(Scanner *scanner, TSLexer *lexer, static bool scan_heredoc_content(Scanner *scanner, TSLexer *lexer,
enum TokenType middle_type, enum TokenType middle_type,
enum TokenType end_type) { enum TokenType end_type) {
bool did_advance = false; bool did_advance = false;
Heredoc *heredoc = array_back(&scanner->heredocs); Heredoc *heredoc = array_back(&scanner->heredocs);
@@ -451,7 +451,7 @@ static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
advance(lexer); advance(lexer);
lexer->mark_end(lexer); lexer->mark_end(lexer);
while (lexer->lookahead == '#' || lexer->lookahead == '=' || while (lexer->lookahead == '#' || lexer->lookahead == '=' ||
lexer->lookahead == '!') { lexer->lookahead == '!') {
advance(lexer); advance(lexer);
} }
while (iswspace(lexer->lookahead)) { while (iswspace(lexer->lookahead)) {
@@ -473,7 +473,7 @@ static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
} }
if ((valid_symbols[HEREDOC_BODY_BEGINNING] || if ((valid_symbols[HEREDOC_BODY_BEGINNING] ||
valid_symbols[SIMPLE_HEREDOC_BODY]) && valid_symbols[SIMPLE_HEREDOC_BODY]) &&
scanner->heredocs.size > 0 && !array_back(&scanner->heredocs)->started && scanner->heredocs.size > 0 && !array_back(&scanner->heredocs)->started &&
!in_error_recovery(valid_symbols)) { !in_error_recovery(valid_symbols)) {
return scan_heredoc_content(scanner, lexer, HEREDOC_BODY_BEGINNING, return scan_heredoc_content(scanner, lexer, HEREDOC_BODY_BEGINNING,
@@ -580,12 +580,12 @@ static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
} }
if ((valid_symbols[VARIABLE_NAME] || valid_symbols[FILE_DESCRIPTOR] || if ((valid_symbols[VARIABLE_NAME] || valid_symbols[FILE_DESCRIPTOR] ||
valid_symbols[HEREDOC_ARROW]) && valid_symbols[HEREDOC_ARROW]) &&
!valid_symbols[REGEX_NO_SLASH] && !in_error_recovery(valid_symbols)) { !valid_symbols[REGEX_NO_SLASH] && !in_error_recovery(valid_symbols)) {
for (;;) { for (;;) {
if ((lexer->lookahead == ' ' || lexer->lookahead == '\t' || if ((lexer->lookahead == ' ' || lexer->lookahead == '\t' ||
lexer->lookahead == '\r' || lexer->lookahead == '\r' ||
(lexer->lookahead == '\n' && !valid_symbols[NEWLINE])) && (lexer->lookahead == '\n' && !valid_symbols[NEWLINE])) &&
!valid_symbols[EXPANSION_WORD]) { !valid_symbols[EXPANSION_WORD]) {
skip(lexer); skip(lexer);
} else if (lexer->lookahead == '\\') { } else if (lexer->lookahead == '\\') {
@@ -616,8 +616,8 @@ static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
// no '*', '@', '?', '-', '$', '0', '_' // no '*', '@', '?', '-', '$', '0', '_'
if (!valid_symbols[EXPANSION_WORD] && if (!valid_symbols[EXPANSION_WORD] &&
(lexer->lookahead == '*' || lexer->lookahead == '@' || (lexer->lookahead == '*' || lexer->lookahead == '@' ||
lexer->lookahead == '?' || lexer->lookahead == '-' || lexer->lookahead == '?' || lexer->lookahead == '-' ||
lexer->lookahead == '0' || lexer->lookahead == '_')) { lexer->lookahead == '0' || lexer->lookahead == '_')) {
lexer->mark_end(lexer); lexer->mark_end(lexer);
advance(lexer); advance(lexer);
if (lexer->lookahead == '=' || lexer->lookahead == '[' || if (lexer->lookahead == '=' || lexer->lookahead == '[' ||
@@ -707,10 +707,10 @@ static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
} }
if (lexer->lookahead == '=' || lexer->lookahead == '[' || if (lexer->lookahead == '=' || lexer->lookahead == '[' ||
(lexer->lookahead == ':' && !valid_symbols[CLOSING_BRACE] && (lexer->lookahead == ':' && !valid_symbols[CLOSING_BRACE] &&
!valid_symbols !valid_symbols
[OPENING_PAREN]) || // TODO(amaanq): more cases for regular word [OPENING_PAREN]) || // TODO(amaanq): more cases for regular word
// chars but not variable names for function // chars but not variable names for function
// words, only handling : for now? #235 // words, only handling : for now? #235
lexer->lookahead == '%' || lexer->lookahead == '%' ||
(lexer->lookahead == '#' && !is_number) || lexer->lookahead == '@' || (lexer->lookahead == '#' && !is_number) || lexer->lookahead == '@' ||
(lexer->lookahead == '-' && valid_symbols[CLOSING_BRACE])) { (lexer->lookahead == '-' && valid_symbols[CLOSING_BRACE])) {
@@ -737,7 +737,7 @@ static bool scan(Scanner *scanner, TSLexer *lexer, const bool *valid_symbols) {
regex: regex:
if ((valid_symbols[REGEX] || valid_symbols[REGEX_NO_SLASH] || if ((valid_symbols[REGEX] || valid_symbols[REGEX_NO_SLASH] ||
valid_symbols[REGEX_NO_SPACE]) && valid_symbols[REGEX_NO_SPACE]) &&
!in_error_recovery(valid_symbols)) { !in_error_recovery(valid_symbols)) {
if (valid_symbols[REGEX] || valid_symbols[REGEX_NO_SPACE]) { if (valid_symbols[REGEX] || valid_symbols[REGEX_NO_SPACE]) {
while (iswspace(lexer->lookahead)) { while (iswspace(lexer->lookahead)) {
@@ -747,7 +747,7 @@ regex:
if ((lexer->lookahead != '"' && lexer->lookahead != '\'') || if ((lexer->lookahead != '"' && lexer->lookahead != '\'') ||
((lexer->lookahead == '$' || lexer->lookahead == '\'') && ((lexer->lookahead == '$' || lexer->lookahead == '\'') &&
valid_symbols[REGEX_NO_SLASH]) || valid_symbols[REGEX_NO_SLASH]) ||
(lexer->lookahead == '\'' && valid_symbols[REGEX_NO_SPACE])) { (lexer->lookahead == '\'' && valid_symbols[REGEX_NO_SPACE])) {
typedef struct { typedef struct {
bool done; bool done;
@@ -905,8 +905,8 @@ regex:
} }
lexer->result_symbol = valid_symbols[REGEX_NO_SLASH] ? REGEX_NO_SLASH lexer->result_symbol = valid_symbols[REGEX_NO_SLASH] ? REGEX_NO_SLASH
: valid_symbols[REGEX_NO_SPACE] ? REGEX_NO_SPACE : valid_symbols[REGEX_NO_SPACE] ? REGEX_NO_SPACE
: REGEX; : REGEX;
if (valid_symbols[REGEX] && !state.advanced_once) { if (valid_symbols[REGEX] && !state.advanced_once) {
return false; return false;
} }
@@ -1035,7 +1035,7 @@ extglob_pattern:
} State; } State;
State state = {false, was_non_alpha, scanner->last_glob_paren_depth, 0, State state = {false, was_non_alpha, scanner->last_glob_paren_depth, 0,
0}; 0};
while (!state.done) { while (!state.done) {
switch (lexer->lookahead) { switch (lexer->lookahead) {
case '\0': case '\0':
@@ -1261,7 +1261,7 @@ void *tree_sitter_shellspec_external_scanner_create() {
} }
bool tree_sitter_shellspec_external_scanner_scan(void *payload, TSLexer *lexer, bool tree_sitter_shellspec_external_scanner_scan(void *payload, TSLexer *lexer,
const bool *valid_symbols) { const bool *valid_symbols) {
Scanner *scanner = (Scanner *)payload; Scanner *scanner = (Scanner *)payload;
return scan(scanner, lexer, valid_symbols); return scan(scanner, lexer, valid_symbols);
} }

View File

@@ -152,7 +152,6 @@ struct TSLanguage {
}; };
static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) { static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {
if (len == 0) return false;
uint32_t index = 0; uint32_t index = 0;
uint32_t size = len - index; uint32_t size = len - index;
while (size > 1) { while (size > 1) {