1
0
Fork 0
mirror of https://github.com/pnx/tree-sitter-dotenv synced 2026-11-01 03:16:46 +01:00

Compare commits

..

12 commits
v1.1.2 ... main

Author SHA1 Message Date
b4f0b0d154 chore: bump version to 1.1.3 2026-10-18 18:19:24 +02:00
b832d23b48 chore: remove C++ casts from array macros 2026-10-18 18:14:43 +02:00
45a576e973
Merge pull request #28 from pnx/dependabot/npm_and_yarn/npm-19b478ba8c
build(deps): bump tree-sitter-cli from 0.27.0 to 0.27.1 in the npm group
2026-10-18 18:12:12 +02:00
dependabot[bot]
79a7e36ac6
build(deps): bump tree-sitter-cli from 0.27.0 to 0.27.1 in the npm group
Bumps the npm group with 1 update: [tree-sitter-cli](https://github.com/tree-sitter/tree-sitter/tree/HEAD/crates/cli/npm).


Updates `tree-sitter-cli` from 0.27.0 to 0.27.1
- [Release notes](https://github.com/tree-sitter/tree-sitter/releases)
- [Commits](https://github.com/tree-sitter/tree-sitter/commits/v0.27.1/crates/cli/npm)

---
updated-dependencies:
- dependency-name: tree-sitter-cli
  dependency-version: 0.27.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-18 11:52:36 +00:00
7f56948e1c
Merge pull request #27 from pnx/26-literal-text-followed-by-a-variable-in-an-unquoted-value-produces-error
fix: parse variable references in unquoted strings
2026-10-06 12:46:49 +02:00
90f212b3ea fix: parse variable references in unquoted strings 2026-09-26 13:07:09 +02:00
a16f203ba0
Merge pull request #25 from pnx/dependabot/cargo/cargo-ee6ecff589
build(deps): update tree-sitter requirement from 0.26.5 to 0.27.0 in the cargo group
2026-09-07 11:38:03 +02:00
2be99c407e
Merge pull request #24 from pnx/dependabot/npm_and_yarn/npm-4d1342ec62
build(deps): bump tree-sitter-cli from 0.26.13 to 0.27.0 in the npm group
2026-09-07 11:37:32 +02:00
dependabot[bot]
36bea371f3
build(deps): update tree-sitter requirement in the cargo group
Updates the requirements on [tree-sitter](https://github.com/tree-sitter/tree-sitter) to permit the latest version.

Updates `tree-sitter` to 0.27.0
- [Release notes](https://github.com/tree-sitter/tree-sitter/releases)
- [Commits](https://github.com/tree-sitter/tree-sitter/compare/v0.26.5...v0.27.0)

---
updated-dependencies:
- dependency-name: tree-sitter
  dependency-version: 0.27.0
  dependency-type: direct:production
  dependency-group: cargo
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-06 11:52:37 +00:00
dependabot[bot]
5e27c105b1
build(deps): bump tree-sitter-cli in the npm group
Bumps the npm group with 1 update: [tree-sitter-cli](https://github.com/tree-sitter/tree-sitter/tree/HEAD/crates/cli/npm).


Updates `tree-sitter-cli` from 0.26.13 to 0.27.0
- [Release notes](https://github.com/tree-sitter/tree-sitter/releases)
- [Commits](https://github.com/tree-sitter/tree-sitter/commits/v0.27.0/crates/cli/npm)

---
updated-dependencies:
- dependency-name: tree-sitter-cli
  dependency-version: 0.27.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-09-06 11:52:23 +00:00
e8f9198b01
Merge pull request #23 from pnx/dependabot/npm_and_yarn/npm-6ad5b8dc86
build(deps): bump tree-sitter-cli from 0.26.12 to 0.26.13 in the npm group
2026-08-31 13:45:12 +02:00
dependabot[bot]
55f2fb13f6
build(deps): bump tree-sitter-cli in the npm group
Bumps the npm group with 1 update: [tree-sitter-cli](https://github.com/tree-sitter/tree-sitter/tree/HEAD/crates/cli/npm).


Updates `tree-sitter-cli` from 0.26.12 to 0.26.13
- [Release notes](https://github.com/tree-sitter/tree-sitter/releases)
- [Commits](https://github.com/tree-sitter/tree-sitter/commits/v0.26.13/crates/cli/npm)

---
updated-dependencies:
- dependency-name: tree-sitter-cli
  dependency-version: 0.26.13
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-30 11:52:40 +00:00
13 changed files with 1203 additions and 620 deletions

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.13)
project(tree-sitter-dotenv
VERSION "1.1.2"
VERSION "1.1.3"
DESCRIPTION "Dotenv grammar for tree-sitter"
HOMEPAGE_URL "https://github.com/pnx/tree-sitter-dotenv"
LANGUAGES C)

View file

@ -1,7 +1,7 @@
[package]
name = "tree-sitter-dotenv"
description = "Dotenv grammar for tree-sitter"
version = "1.1.2"
version = "1.1.3"
license = "MIT"
readme = "README.md"
keywords = ["incremental", "parsing", "tree-sitter", "dotenv"]
@ -23,4 +23,4 @@ tree-sitter-language = "0.1"
cc = "1.0.87"
[dev-dependencies]
tree-sitter = "0.26.5"
tree-sitter = "0.27.0"

2
Makefile generated
View file

@ -2,7 +2,7 @@ ifeq ($(OS),Windows_NT)
$(error Windows is not supported)
endif
VERSION := 1.1.2
VERSION := 1.1.3
LANGUAGE_NAME := tree-sitter-dotenv

View file

@ -45,10 +45,12 @@ module.exports = grammar({
comment: _ => /\#[^\n]*/,
identifier: _ => /[A-Za-z_][A-Za-z0-9_]*/,
variable: $ => seq('$', choice(
$.identifier,
seq('{', $.identifier, '}')
)),
variable: $ => choice(
seq('$', $.identifier),
$._braced_variable,
),
_braced_variable: $ => seq('$', '{', $.identifier, '}'),
_value: $ => choice(
$.string,
@ -66,7 +68,35 @@ module.exports = grammar({
$._unquoted_string,
),
_unquoted_string: $ => alias(/[^\#\s\"\'\$]+(?:[ \t]+[^\#\s\"\'\$]+)+/, $.string_content),
_unquoted_string: $ => choice(
alias($._unquoted_content, $.string_content),
seq(
choice(
alias($.value, $.string_content),
alias($.boolean, $.string_content),
alias($.decimal, $.string_content),
alias($.hexadecimal, $.string_content),
alias($.float, $.string_content),
alias($._unquoted_content, $.string_content),
),
alias($._braced_variable, $.variable),
optional(choice(
alias($.value, $.string_content),
alias($._unquoted_content, $.string_content),
)),
),
),
_unquoted_content: _ => token(choice(
/[^\#\s\"\'\$]+(?:[ \t]+[^\#\s\"\'\$]+)+/,
seq(
/[^\#\s\"\'\$]+(?:[ \t]+[^\#\s\"\'\$]+)*/,
repeat1(seq(
/\$[A-Za-z_][A-Za-z0-9_]*/,
optional(/(?:[ \t]*[^\#\s\"\'\$]+)+/),
)),
),
)),
_literal_string: $ => seq(
"'",

12
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "tree-sitter-dotenv",
"version": "1.1.1",
"version": "1.1.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "tree-sitter-dotenv",
"version": "1.1.1",
"version": "1.1.2",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@ -15,7 +15,7 @@
},
"devDependencies": {
"prebuildify": "^6.0.1",
"tree-sitter-cli": "^0.26.12"
"tree-sitter-cli": "^0.27.1"
},
"peerDependencies": {
"tree-sitter": "^0.21.1"
@ -338,9 +338,9 @@
}
},
"node_modules/tree-sitter-cli": {
"version": "0.26.12",
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.26.12.tgz",
"integrity": "sha512-rIdMAm6nv75MVFoZ7UTaLVB1OG5h3ZSlCZEp5pne4gOUTalJIkL0A1NlYBg0oEl/d7gvIyc2Y5Jz8m5Xj+NOEw==",
"version": "0.27.1",
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.27.1.tgz",
"integrity": "sha512-WFPEjxwscCjZP9uYj0rxT2TyGBkDcXUkGTthrMpxZFGvzXEYsbC3J0633Ps8dd2mMsdsbU8oVwmQ148lLHI7Xw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "tree-sitter-dotenv",
"version": "1.1.2",
"version": "1.1.3",
"description": "Dotenv grammar for tree-sitter",
"repository": "github:pnx/tree-sitter-dotenv",
"license": "MIT",
@ -27,7 +27,7 @@
},
"devDependencies": {
"prebuildify": "^6.0.1",
"tree-sitter-cli": "^0.26.12"
"tree-sitter-cli": "^0.27.1"
},
"peerDependencies": {
"tree-sitter": "^0.21.1"

View file

@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "tree-sitter-dotenv"
description = "Dotenv grammar for tree-sitter"
version = "1.1.2"
version = "1.1.3"
keywords = ["incremental", "parsing", "tree-sitter", "dotenv"]
classifiers = [
"Intended Audience :: Developers",

222
src/grammar.json generated
View file

@ -143,6 +143,28 @@
"value": "[A-Za-z_][A-Za-z0-9_]*"
},
"variable": {
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "$"
},
{
"type": "SYMBOL",
"name": "identifier"
}
]
},
{
"type": "SYMBOL",
"name": "_braced_variable"
}
]
},
"_braced_variable": {
"type": "SEQ",
"members": [
{
@ -150,30 +172,16 @@
"value": "$"
},
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "{"
},
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "STRING",
"value": "}"
}
]
}
]
"type": "STRING",
"value": "{"
},
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "STRING",
"value": "}"
}
]
},
@ -220,13 +228,167 @@
]
},
"_unquoted_string": {
"type": "ALIAS",
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_unquoted_content"
},
"named": true,
"value": "string_content"
},
{
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "value"
},
"named": true,
"value": "string_content"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "boolean"
},
"named": true,
"value": "string_content"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "decimal"
},
"named": true,
"value": "string_content"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "hexadecimal"
},
"named": true,
"value": "string_content"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "float"
},
"named": true,
"value": "string_content"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_unquoted_content"
},
"named": true,
"value": "string_content"
}
]
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_braced_variable"
},
"named": true,
"value": "variable"
},
{
"type": "CHOICE",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "value"
},
"named": true,
"value": "string_content"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "_unquoted_content"
},
"named": true,
"value": "string_content"
}
]
},
{
"type": "BLANK"
}
]
}
]
}
]
},
"_unquoted_content": {
"type": "TOKEN",
"content": {
"type": "PATTERN",
"value": "[^\\#\\s\\\"\\'\\$]+(?:[ \\t]+[^\\#\\s\\\"\\'\\$]+)+"
},
"named": true,
"value": "string_content"
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "[^\\#\\s\\\"\\'\\$]+(?:[ \\t]+[^\\#\\s\\\"\\'\\$]+)+"
},
{
"type": "SEQ",
"members": [
{
"type": "PATTERN",
"value": "[^\\#\\s\\\"\\'\\$]+(?:[ \\t]+[^\\#\\s\\\"\\'\\$]+)*"
},
{
"type": "REPEAT1",
"content": {
"type": "SEQ",
"members": [
{
"type": "PATTERN",
"value": "\\$[A-Za-z_][A-Za-z0-9_]*"
},
{
"type": "CHOICE",
"members": [
{
"type": "PATTERN",
"value": "(?:[ \\t]*[^\\#\\s\\\"\\'\\$]+)+"
},
{
"type": "BLANK"
}
]
}
]
}
}
]
}
]
}
},
"_literal_string": {
"type": "SEQ",

1250
src/parser.c generated

File diff suppressed because it is too large Load diff

View file

@ -50,18 +50,12 @@ extern "C" {
/// memory allocated for the array's contents.
#define array_clear(self) ((self)->size = 0)
#ifdef __cplusplus
#define _array__cast(self, expr) (decltype((self)->contents))(expr)
#else
#define _array__cast(self, expr) (expr)
#endif
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
/// less than the array's current capacity, this function has no effect.
#define array_reserve(self, new_capacity) \
((self)->contents = _array__cast(self, _array__reserve( \
(void *)(self)->contents, &(self)->capacity, \
array_elem_size(self), new_capacity)) \
#define array_reserve(self, new_capacity) \
((self)->contents = _array__reserve( \
(void *)(self)->contents, &(self)->capacity, \
array_elem_size(self), new_capacity) \
)
/// Free any memory allocated for this array. Note that this does not free any
@ -77,10 +71,10 @@ extern "C" {
/// Push a new `element` onto the end of the array.
#define array_push(self, element) \
do { \
(self)->contents = _array__cast(self, _array__grow( \
(self)->contents = _array__grow( \
(void *)(self)->contents, (self)->size, &(self)->capacity, \
1, array_elem_size(self) \
)); \
); \
(self)->contents[(self)->size++] = (element); \
} while(0)
@ -89,10 +83,10 @@ extern "C" {
#define array_grow_by(self, count) \
do { \
if ((count) == 0) break; \
(self)->contents = _array__cast(self, _array__grow( \
(self)->contents = _array__grow( \
(self)->contents, (self)->size, &(self)->capacity, \
count, array_elem_size(self) \
)); \
); \
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
(self)->size += (count); \
} while (0)
@ -104,26 +98,26 @@ extern "C" {
/// Append `count` elements to the end of the array, reading their values from the
/// `contents` pointer.
#define array_extend(self, count, other_contents) \
((self)->contents = _array__cast(self, _array__splice( \
(self)->contents = _array__splice( \
(void*)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), (self)->size, 0, count, other_contents \
)))
)
/// Remove `old_count` elements from the array starting at the given `index`. At
/// the same index, insert `new_count` new elements, reading their values from the
/// `new_contents` pointer.
#define array_splice(self, _index, old_count, new_count, new_contents) \
((self)->contents = _array__cast(self, _array__splice( \
(self)->contents = _array__splice( \
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), _index, old_count, new_count, new_contents \
)))
)
/// Insert one `element` into the array at the given `index`.
#define array_insert(self, _index, element) \
((self)->contents = _array__cast(self, _array__splice( \
(self)->contents = _array__splice( \
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), _index, 0, 1, &(element) \
)))
)
/// Remove one element from the array at the given `index`.
#define array_erase(self, _index) \
@ -134,17 +128,17 @@ extern "C" {
/// Assign the contents of one array to another, reallocating if necessary.
#define array_assign(self, other) \
((self)->contents = _array__cast(self, _array__assign( \
(self)->contents = _array__assign( \
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
(const void *)(other)->contents, (other)->size, array_elem_size(self) \
)))
)
/// Swap one array with another
#define array_swap(self, other) \
do { \
void *_array_swap_tmp = (void *)(self)->contents; \
(self)->contents = (other)->contents; \
(other)->contents = _array__cast(other, _array_swap_tmp); \
(other)->contents = _array_swap_tmp; \
_array__swap(&(self)->size, &(self)->capacity, \
&(other)->size, &(other)->capacity); \
} while (0)

View file

@ -0,0 +1,161 @@
================================================================================
Boolean prefixes become string content
================================================================================
PLAIN_TRUE=true
TRUE_PREFIX=true${APP_NAME}
PLAIN_FALSE=false
FALSE_PREFIX=false${APP_NAME}
--------------------------------------------------------------------------------
(document
(assignment
(identifier)
(boolean))
(assignment
(identifier)
(string
(string_content)
(variable (identifier))))
(assignment
(identifier)
(boolean))
(assignment
(identifier)
(string
(string_content)
(variable (identifier)))))
================================================================================
Numeric prefixes become string content
================================================================================
PLAIN_INTEGER=123
INTEGER_PREFIX=123${APP_NAME}
PLAIN_NEGATIVE=-123
NEGATIVE_PREFIX=-123${APP_NAME}
PLAIN_HEX=0xFF
HEX_PREFIX=0xFF${APP_NAME}
PLAIN_FLOAT=1.5
FLOAT_PREFIX=1.5${APP_NAME}
PLAIN_NEGATIVE_FLOAT=-1.5
NEGATIVE_FLOAT_PREFIX=-1.5${APP_NAME}
--------------------------------------------------------------------------------
(document
(assignment
(identifier)
(number (integer (decimal))))
(assignment
(identifier)
(string
(string_content)
(variable (identifier))))
(assignment
(identifier)
(number (integer (decimal))))
(assignment
(identifier)
(string
(string_content)
(variable (identifier))))
(assignment
(identifier)
(number (integer (hexadecimal))))
(assignment
(identifier)
(string
(string_content)
(variable (identifier))))
(assignment
(identifier)
(number (float)))
(assignment
(identifier)
(string
(string_content)
(variable (identifier))))
(assignment
(identifier)
(number (float)))
(assignment
(identifier)
(string
(string_content)
(variable (identifier)))))
================================================================================
Scalar prefixes with suffixes and comments
================================================================================
BOOL=true${APP_NAME}-suffix # comment
NUMBER=123${APP_NAME} suffix words
--------------------------------------------------------------------------------
(document
(assignment
(identifier)
(string
(string_content)
(variable (identifier))
(string_content)))
(comment)
(assignment
(identifier)
(string
(string_content)
(variable (identifier))
(string_content))))
================================================================================
Bare boolean-prefixed references are literal strings
================================================================================
BOOL=true$APP_NAME
BOOL=false$APP_NAME
--------------------------------------------------------------------------------
(document
(assignment (identifier) (string (string_content)))
(assignment (identifier) (string (string_content))))
================================================================================
Bare decimal-prefixed references are literal strings
================================================================================
NUMBER=123$APP_NAME
NUMBER=-123$APP_NAME
--------------------------------------------------------------------------------
(document
(assignment (identifier) (string (string_content)))
(assignment (identifier) (string (string_content))))
================================================================================
Bare hexadecimal-prefixed references are literal strings
================================================================================
HEX=0xFF$APP_NAME
--------------------------------------------------------------------------------
(document
(assignment (identifier) (string (string_content))))
================================================================================
Bare float-prefixed references are literal strings
================================================================================
FLOAT=1.5$APP_NAME
FLOAT=-1.5$APP_NAME
--------------------------------------------------------------------------------
(document
(assignment (identifier) (string (string_content)))
(assignment (identifier) (string (string_content))))

View file

@ -42,3 +42,85 @@ MULTIPLE = "variable is: ${VARIABLE}, and $ANOTHER !!!"
(variable
(identifier))
(string_content))))
================================================================================
Unquoted braced variables with prefixes
================================================================================
BASIC = prefix${VARIABLE}
VITE_APP_NAME=xxx${APP_NAME}
SUFFIX = prefix${VARIABLE}-suffix
MULTIWORD = prefix words${VARIABLE} suffix words # comment
--------------------------------------------------------------------------------
(document
(assignment
key: (identifier)
value: (string
(string_content)
(variable
(identifier))))
(assignment
key: (identifier)
value: (string
(string_content)
(variable
(identifier))))
(assignment
key: (identifier)
value: (string
(string_content)
(variable
(identifier))
(string_content)))
(assignment
key: (identifier)
value: (string
(string_content)
(variable
(identifier))
(string_content)))
(comment))
================================================================================
Unquoted bare references with prefixes are literal strings
================================================================================
VITE_APP_NAME=xxx$APP_NAME
NAME=XXX$APP_NAME
SUFFIX=xxx$APP_NAME-suffix
MULTIPLE=xxx$APP_NAME$OTHER
MULTIWORD=prefix words$APP_NAME suffix words # comment
--------------------------------------------------------------------------------
(document
(assignment (identifier) (string (string_content)))
(assignment (identifier) (string (string_content)))
(assignment (identifier) (string (string_content)))
(assignment (identifier) (string (string_content)))
(assignment (identifier) (string (string_content)))
(comment))
================================================================================
Literal bare references alongside braced interpolation
================================================================================
PREFIX=xxx$LITERAL${APP_NAME}
SUFFIX=xxx${APP_NAME}suffix$LITERAL
--------------------------------------------------------------------------------
(document
(assignment
(identifier)
(string
(string_content)
(variable (identifier))))
(assignment
(identifier)
(string
(string_content)
(variable (identifier))
(string_content))))

View file

@ -15,7 +15,7 @@
}
],
"metadata": {
"version": "1.1.2",
"version": "1.1.3",
"license": "MIT",
"description": "Dotenv grammar for tree-sitter",
"authors": [