From 70cd74f6d3ead703a1483f85f5f8e9e3363e266f Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Tue, 9 Sep 2025 16:46:25 +0300 Subject: [PATCH 01/34] Update Snapshot file --- .../test/__snapshots__/cli.test.ts.snap | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap index ae75717c3..1baad2c63 100644 --- a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap +++ b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap @@ -93,10 +93,10 @@ test/fixtures/multiple-rule-offenses.html.erb:5:3 test/fixtures/multiple-rule-offenses.html.erb:10:1 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -107,10 +107,10 @@ test/fixtures/multiple-rule-offenses.html.erb:10:1 test/fixtures/multiple-rule-offenses.html.erb:10:4 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -121,7 +121,7 @@ test/fixtures/multiple-rule-offenses.html.erb:10:4 test/fixtures/multiple-rule-offenses.html.erb:3:20 1 │ - 2 │ + 2 │ → 3 │
│ ~~ 4 │ @@ -135,7 +135,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:20 test/fixtures/multiple-rule-offenses.html.erb:3:8 1 │ - 2 │ + 2 │ → 3 │
│ ~~~~~ 4 │ @@ -149,7 +149,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:8 test/fixtures/multiple-rule-offenses.html.erb:3:34 1 │ - 2 │ + 2 │ → 3 │
│ ~~~ 4 │ @@ -162,7 +162,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:34 test/fixtures/multiple-rule-offenses.html.erb:4:3 - 2 │ + 2 │ 3 │
→ 4 │ │ ~~~ @@ -191,7 +191,7 @@ test/fixtures/multiple-rule-offenses.html.erb:5:14 test/fixtures/multiple-rule-offenses.html.erb:3:14 1 │ - 2 │ + 2 │ → 3 │
│ ~~~~~ 4 │ @@ -233,10 +233,10 @@ test/fixtures/multiple-rule-offenses.html.erb:5:14 test/fixtures/multiple-rule-offenses.html.erb:8:0 6 │
- 7 │ + 7 │ → 8 │

│ ~~~~~~~~~ - 9 │ + 9 │ 10 │ Nested @@ -247,10 +247,10 @@ test/fixtures/multiple-rule-offenses.html.erb:8:0 test/fixtures/multiple-rule-offenses.html.erb:10:4 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -260,7 +260,7 @@ test/fixtures/multiple-rule-offenses.html.erb:10:4 test/fixtures/multiple-rule-offenses.html.erb:4:2 - 2 │ + 2 │ 3 │
→ 4 │ │ ~~~~~~~ @@ -341,7 +341,7 @@ test/fixtures/few-rule-offenses.html.erb:3:3 test/fixtures/few-rule-offenses.html.erb:9:5 - 7 │ + 7 │ 8 │
→ 9 │
│ ~~~~~~~~~~~~~~ @@ -355,10 +355,10 @@ test/fixtures/few-rule-offenses.html.erb:9:5 test/fixtures/few-rule-offenses.html.erb:6:0 4 │
- 5 │ + 5 │ → 6 │

│ ~~~~~~~~~ - 7 │ + 7 │ 8 │
From 12d63d73425d109fc59401ee4924786146d260fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Sep 2025 12:04:38 +0300 Subject: [PATCH 02/34] Bump vite from 6.3.5 to 6.3.6 in the npm_and_yarn group across 1 directory (#493) Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 6.3.5 to 6.3.6 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- playground/package.json | 2 +- yarn.lock | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/playground/package.json b/playground/package.json index 9590638d4..f0a852fa7 100644 --- a/playground/package.json +++ b/playground/package.json @@ -28,7 +28,7 @@ "lz-string": "^1.5.0", "monaco-editor": "^0.52.2", "prismjs": "^1.30.0", - "vite": "^6.3.5" + "vite": "^6.3.6" }, "devDependencies": { "@types/express": "^4.17.21", diff --git a/yarn.lock b/yarn.lock index 2deee4ec1..02d498018 100644 --- a/yarn.lock +++ b/yarn.lock @@ -549,16 +549,6 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c" integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== -"@herb-tools/node@0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@herb-tools/node/-/node-0.6.1.tgz#90f14130a3ba141a1bf25a63b28c4914c7caf53c" - integrity sha512-iXJJpbLik9Eb1tIGwj54jQ1yjeZtV7udElWT96WDEar/HT7y7ICQc3VmrEGiW35rVAvlNBa+v/MhJsgZgF893w== - dependencies: - "@herb-tools/core" "0.6.1" - "@mapbox/node-pre-gyp" "^2.0.0" - node-addon-api "^5.1.0" - node-pre-gyp-github "^2.0.0" - "@hotwired/stimulus-webpack-helpers@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@hotwired/stimulus-webpack-helpers/-/stimulus-webpack-helpers-1.0.1.tgz#4cd74487adeca576c9865ac2b9fe5cb20cef16dd" @@ -10181,10 +10171,10 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -vite@^6.3.5: - version "6.3.5" - resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.5.tgz#fec73879013c9c0128c8d284504c6d19410d12a3" - integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ== +vite@^6.3.6: + version "6.3.6" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.6.tgz#69a976b64930750d40219fbc68c5200874d315c1" + integrity sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA== dependencies: esbuild "^0.25.0" fdir "^6.4.4" From 63365958676b633f6810fe957d39860f3692ae2f Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sat, 13 Sep 2025 18:57:49 +0300 Subject: [PATCH 03/34] Bump Prism to `v1.5.1` (#495) Upgrade Prism to [`v1.5.1`](https://github.com/ruby/prism/releases/tag/v1.5.1), also see [`v1.5.0`](https://github.com/ruby/prism/releases/tag/v1.5.0). --- CONTRIBUTING.md | 3 +-- Gemfile | 2 +- Gemfile.lock | 6 +++--- javascript/packages/browser/test/browser.test.ts | 2 +- javascript/packages/node-wasm/test/node-wasm.test.ts | 2 +- javascript/packages/node/test/node.test.ts | 2 +- test/herb_test.rb | 9 +++++++++ 7 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 test/herb_test.rb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 66ad5fd66..e0bdc6276 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ If you encounter any issues when following along with this file please dont hesi - [**Clang 19**](https://clang.llvm.org): The compiler used to build this project. - [**Clang Format 19**](https://clang.llvm.org/docs/ClangFormat.html): For formatting the project. - [**Clang Tidy 19**](https://clang.llvm.org/extra/clang-tidy/): For linting the project. -- [**Prism Ruby Parser v1.4.0**](https://github.com/ruby/prism/releases/tag/v1.4.0): We use Prism for Parsing the Ruby Source Code in the HTML+ERB files. +- [**Prism Ruby Parser v1.5.1**](https://github.com/ruby/prism/releases/tag/v1.5.1): We use Prism for Parsing the Ruby Source Code in the HTML+ERB files. - [**Ruby**](https://www.ruby-lang.org/en/): We need Ruby as a dependency for `bundler`. - [**Bundler**](https://bundler.io): We are using `bundler` to build [`prism`](https://github.com/ruby/prism) from source so we can build `herb` against it. - [**Emscripten**](https://emscripten.org): For the WebAssembly build of `libherb` so it can be used in the browser using the [`@herb-tools/browser`](https://github.com/marcoroth/herb/blob/main/javascript/packages/browser) package. @@ -159,4 +159,3 @@ The integration was successful if you see: Integration successful! ``` - diff --git a/Gemfile b/Gemfile index fbe4490fe..b23142024 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,7 @@ source "https://rubygems.org" gemspec -gem "prism", github: "ruby/prism", tag: "v1.4.0" +gem "prism", github: "ruby/prism", tag: "v1.5.1" gem "actionview", "~> 8.0" gem "lz_string" diff --git a/Gemfile.lock b/Gemfile.lock index 240315fc6..9c6dc596c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,10 +9,10 @@ GIT GIT remote: https://github.com/ruby/prism.git - revision: 266f83de6a2b0c1557404dde33ad3d41ceba7043 - tag: v1.4.0 + revision: 23f16d31a7c57c4b927e1e3ec8f1281b45e7cb9f + tag: v1.5.1 specs: - prism (1.4.0) + prism (1.5.1) PATH remote: . diff --git a/javascript/packages/browser/test/browser.test.ts b/javascript/packages/browser/test/browser.test.ts index 11c31d9fe..6fb22384e 100644 --- a/javascript/packages/browser/test/browser.test.ts +++ b/javascript/packages/browser/test/browser.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/browser", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/browser@0.7.0, @herb-tools/core@0.7.0, libprism@1.4.0, libherb@0.7.0 (WebAssembly)") + expect(version).toBe("@herb-tools/browser@0.7.0, @herb-tools/core@0.7.0, libprism@1.5.1, libherb@0.7.0 (WebAssembly)") }) test("parse() can process a simple template", async () => { diff --git a/javascript/packages/node-wasm/test/node-wasm.test.ts b/javascript/packages/node-wasm/test/node-wasm.test.ts index ef0e15a10..343bd2989 100644 --- a/javascript/packages/node-wasm/test/node-wasm.test.ts +++ b/javascript/packages/node-wasm/test/node-wasm.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/node-wasm", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/node-wasm@0.7.0, @herb-tools/core@0.7.0, libprism@1.4.0, libherb@0.7.0 (WebAssembly)") + expect(version).toBe("@herb-tools/node-wasm@0.7.0, @herb-tools/core@0.7.0, libprism@1.5.1, libherb@0.7.0 (WebAssembly)") }) test("parse() can process a simple template", async () => { diff --git a/javascript/packages/node/test/node.test.ts b/javascript/packages/node/test/node.test.ts index 62bd34dbb..8a3108b1c 100644 --- a/javascript/packages/node/test/node.test.ts +++ b/javascript/packages/node/test/node.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/node", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/node@0.7.0, @herb-tools/core@0.7.0, libprism@1.4.0, libherb@0.7.0 (Node.js C++ native extension)") + expect(version).toBe("@herb-tools/node@0.7.0, @herb-tools/core@0.7.0, libprism@1.5.1, libherb@0.7.0 (Node.js C++ native extension)") }) test("parse() can process a simple template", async () => { diff --git a/test/herb_test.rb b/test/herb_test.rb new file mode 100644 index 000000000..ce1965ca0 --- /dev/null +++ b/test/herb_test.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require_relative "test_helper" + +class HerbTest < Minitest::Spec + test "version" do + assert_equal "herb gem v0.7.0, libprism v1.5.1, libherb v0.7.0 (Ruby C native extension)", Herb.version + end +end From bd1a2eb4bfdb94767fa870bda0a3dd7d8f5cdc56 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sat, 13 Sep 2025 19:25:53 +0300 Subject: [PATCH 04/34] Allow Colon `:` in HTML Attribute Names (#496) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pull request updates the parser to allow HTML Attributes to start with a colon, which is typical in the Vue.js style: ```html
``` Previously, this caused a syntax error: ```js @ UnexpectedError (location: (1:5)-(1:6)) ├── message: "Unexpected Token. Expected: `TOKEN_IDENTIFIER, TOKEN_AT, TOKEN_ERB_START,TOKEN_WHITESPACE, or TOKEN_NEWLINE`, found: `TOKEN_COLON`." ├── description: "Unexpected Token" ├── expected: "TOKEN_IDENTIFIER, TOKEN_AT, TOKEN_ERB_START,TOKEN_WHITESPACE, or TOKEN_NEWLINE" └── found: "TOKEN_COLON" ``` Now this parses as: ```js @ HTMLAttributeNode (location: (1:5)-(1:21)) ├── errors: [] ├── name: │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:11)) │ ├── errors: [] │ └── children: (1 item) │ └── @ LiteralNode (location: (1:5)-(1:11)) │ ├── errors: [] │ └── content: ":class" │ ├── equals: "=" (location: (1:11)-(1:12)) └── value: └── @ HTMLAttributeValueNode (location: (1:12)-(1:21)) ├── errors: [] ├── open_quote: """ (location: (1:12)-(1:13)) ├── children: (1 item) │ └── @ LiteralNode (location: (1:13)-(1:20)) │ ├── errors: [] │ └── content: "classes" │ │ ├── close_quote: """ (location: (1:20)-(1:21)) └── quoted: true ``` --- src/parser.c | 14 +++ test/parser/attributes_test.rb | 32 +++++++ ...value_48a4fb492a8544d35ffb4d589f5a602c.txt | 42 +++++++++ ...tiple_4f1d1b98f3b9c869967323f090d9afee.txt | 89 +++++++++++++++++++ ...value_14a36e2ed468092336d9f6080e939190.txt | 33 +++++++ ...butes_355d0da3aae174783058e2ccec41ac05.txt | 82 +++++++++++++++++ ...valid_c037b25064b31d22c6c195361999c5b8.txt | 49 ++++++++++ ...valid_e30b590c384b162d5019345f8083bfdb.txt | 42 +++++++++ ...valid_f2b2354b82896dec0458b506ae56eb58.txt | 49 ++++++++++ ...yntax_e3d2d0afe1a0d7a4f71d0831ed0a9306.txt | 42 +++++++++ 10 files changed, 474 insertions(+) create mode 100644 test/snapshots/parser/attributes_test/test_0038_Vue-style_directive_attribute_with_value_48a4fb492a8544d35ffb4d589f5a602c.txt create mode 100644 test/snapshots/parser/attributes_test/test_0039_Vue-style_directive_attributes_multiple_4f1d1b98f3b9c869967323f090d9afee.txt create mode 100644 test/snapshots/parser/attributes_test/test_0040_Vue-style_directive_attribute_without_value_14a36e2ed468092336d9f6080e939190.txt create mode 100644 test/snapshots/parser/attributes_test/test_0041_Mixed_Vue_directives_and_regular_attributes_355d0da3aae174783058e2ccec41ac05.txt create mode 100644 test/snapshots/parser/attributes_test/test_0042_Standalone_colon_with_space_is_invalid_c037b25064b31d22c6c195361999c5b8.txt create mode 100644 test/snapshots/parser/attributes_test/test_0043_Colon_immediately_followed_by_attribute_name_is_valid_e30b590c384b162d5019345f8083bfdb.txt create mode 100644 test/snapshots/parser/attributes_test/test_0044_Double_colon_is_invalid_f2b2354b82896dec0458b506ae56eb58.txt create mode 100644 test/snapshots/parser/attributes_test/test_0045_Vue_directive_with_namespace-like_syntax_e3d2d0afe1a0d7a4f71d0831ed0a9306.txt diff --git a/src/parser.c b/src/parser.c index 04573cacb..c7dd7c310 100644 --- a/src/parser.c +++ b/src/parser.c @@ -805,6 +805,20 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) { continue; } + if (parser->current_token->type == TOKEN_COLON) { + lexer_T lexer_copy = *parser->lexer; + token_T* next_token = lexer_next_token(&lexer_copy); + + if (next_token && next_token->type == TOKEN_IDENTIFIER) { + token_free(next_token); + array_append(children, parser_parse_html_attribute(parser)); + + continue; + } + + token_free(next_token); + } + parser_append_unexpected_error( parser, "Unexpected Token", diff --git a/test/parser/attributes_test.rb b/test/parser/attributes_test.rb index acf9f1583..e6cebb610 100644 --- a/test/parser/attributes_test.rb +++ b/test/parser/attributes_test.rb @@ -159,5 +159,37 @@ class AttributesTest < Minitest::Spec test "attribute with backtick containing HTML (invalid)" do assert_parsed_snapshot(%(
Hello`>
)) end + + test "Vue-style directive attribute with value" do + assert_parsed_snapshot(%(
)) + end + + test "Vue-style directive attributes multiple" do + assert_parsed_snapshot(%()) + end + + test "Vue-style directive attribute without value" do + assert_parsed_snapshot(%(
)) + end + + test "Mixed Vue directives and regular attributes" do + assert_parsed_snapshot(%(
)) + end + + test "Standalone colon with space is invalid" do + assert_parsed_snapshot(%(
)) + end + + test "Colon immediately followed by attribute name is valid" do + assert_parsed_snapshot(%(
)) + end + + test "Double colon is invalid" do + assert_parsed_snapshot(%(
)) + end + + test "Vue directive with namespace-like syntax" do + assert_parsed_snapshot(%(
)) + end end end diff --git a/test/snapshots/parser/attributes_test/test_0038_Vue-style_directive_attribute_with_value_48a4fb492a8544d35ffb4d589f5a602c.txt b/test/snapshots/parser/attributes_test/test_0038_Vue-style_directive_attribute_with_value_48a4fb492a8544d35ffb4d589f5a602c.txt new file mode 100644 index 000000000..576387524 --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0038_Vue-style_directive_attribute_with_value_48a4fb492a8544d35ffb4d589f5a602c.txt @@ -0,0 +1,42 @@ +@ DocumentNode (location: (1:0)-(1:30)) +└── children: (1 item) + └── @ HTMLElementNode (location: (1:0)-(1:30)) + ├── open_tag: + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:24)) + │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── tag_closing: ">" (location: (1:23)-(1:24)) + │ ├── children: (1 item) + │ │ └── @ HTMLAttributeNode (location: (1:5)-(1:23)) + │ │ ├── name: + │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:11)) + │ │ │ └── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:5)-(1:11)) + │ │ │ └── content: ":value" + │ │ │ + │ │ │ + │ │ ├── equals: "=" (location: (1:11)-(1:12)) + │ │ └── value: + │ │ └── @ HTMLAttributeValueNode (location: (1:12)-(1:23)) + │ │ ├── open_quote: """ (location: (1:12)-(1:13)) + │ │ ├── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:13)-(1:22)) + │ │ │ └── content: "something" + │ │ │ + │ │ ├── close_quote: """ (location: (1:22)-(1:23)) + │ │ └── quoted: true + │ │ + │ │ + │ └── is_void: false + │ + ├── tag_name: "div" (location: (1:1)-(1:4)) + ├── body: [] + ├── close_tag: + │ └── @ HTMLCloseTagNode (location: (1:24)-(1:30)) + │ ├── tag_opening: "" (location: (1:29)-(1:30)) + │ + ├── is_void: false + └── source: "HTML" \ No newline at end of file diff --git a/test/snapshots/parser/attributes_test/test_0039_Vue-style_directive_attributes_multiple_4f1d1b98f3b9c869967323f090d9afee.txt b/test/snapshots/parser/attributes_test/test_0039_Vue-style_directive_attributes_multiple_4f1d1b98f3b9c869967323f090d9afee.txt new file mode 100644 index 000000000..33ed08233 --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0039_Vue-style_directive_attributes_multiple_4f1d1b98f3b9c869967323f090d9afee.txt @@ -0,0 +1,89 @@ +@ DocumentNode (location: (1:0)-(1:71)) +└── children: (2 items) + ├── @ HTMLElementNode (location: (1:0)-(1:63)) + │ ├── open_tag: + │ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:63)) + │ │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ │ ├── tag_name: "input" (location: (1:1)-(1:6)) + │ │ ├── tag_closing: ">" (location: (1:62)-(1:63)) + │ │ ├── children: (3 items) + │ │ │ ├── @ HTMLAttributeNode (location: (1:7)-(1:20)) + │ │ │ │ ├── name: + │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:7)-(1:13)) + │ │ │ │ │ └── children: (1 item) + │ │ │ │ │ └── @ LiteralNode (location: (1:7)-(1:13)) + │ │ │ │ │ └── content: ":model" + │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ ├── equals: "=" (location: (1:13)-(1:14)) + │ │ │ │ └── value: + │ │ │ │ └── @ HTMLAttributeValueNode (location: (1:14)-(1:20)) + │ │ │ │ ├── open_quote: """ (location: (1:14)-(1:15)) + │ │ │ │ ├── children: (1 item) + │ │ │ │ │ └── @ LiteralNode (location: (1:15)-(1:19)) + │ │ │ │ │ └── content: "user" + │ │ │ │ │ + │ │ │ │ ├── close_quote: """ (location: (1:19)-(1:20)) + │ │ │ │ └── quoted: true + │ │ │ │ + │ │ │ │ + │ │ │ ├── @ HTMLAttributeNode (location: (1:21)-(1:43)) + │ │ │ │ ├── name: + │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:21)-(1:30)) + │ │ │ │ │ └── children: (1 item) + │ │ │ │ │ └── @ LiteralNode (location: (1:21)-(1:30)) + │ │ │ │ │ └── content: ":disabled" + │ │ │ │ │ + │ │ │ │ │ + │ │ │ │ ├── equals: "=" (location: (1:30)-(1:31)) + │ │ │ │ └── value: + │ │ │ │ └── @ HTMLAttributeValueNode (location: (1:31)-(1:43)) + │ │ │ │ ├── open_quote: """ (location: (1:31)-(1:32)) + │ │ │ │ ├── children: (1 item) + │ │ │ │ │ └── @ LiteralNode (location: (1:32)-(1:42)) + │ │ │ │ │ └── content: "isDisabled" + │ │ │ │ │ + │ │ │ │ ├── close_quote: """ (location: (1:42)-(1:43)) + │ │ │ │ └── quoted: true + │ │ │ │ + │ │ │ │ + │ │ │ └── @ HTMLAttributeNode (location: (1:44)-(1:62)) + │ │ │ ├── name: + │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:44)-(1:50)) + │ │ │ │ └── children: (1 item) + │ │ │ │ └── @ LiteralNode (location: (1:44)-(1:50)) + │ │ │ │ └── content: ":class" + │ │ │ │ + │ │ │ │ + │ │ │ ├── equals: "=" (location: (1:50)-(1:51)) + │ │ │ └── value: + │ │ │ └── @ HTMLAttributeValueNode (location: (1:51)-(1:62)) + │ │ │ ├── open_quote: """ (location: (1:51)-(1:52)) + │ │ │ ├── children: (1 item) + │ │ │ │ └── @ LiteralNode (location: (1:52)-(1:61)) + │ │ │ │ └── content: "className" + │ │ │ │ + │ │ │ ├── close_quote: """ (location: (1:61)-(1:62)) + │ │ │ └── quoted: true + │ │ │ + │ │ │ + │ │ └── is_void: false + │ │ + │ ├── tag_name: "input" (location: (1:1)-(1:6)) + │ ├── body: [] + │ ├── close_tag: ∅ + │ ├── is_void: true + │ └── source: "HTML" + │ + └── @ HTMLCloseTagNode (location: (1:63)-(1:71)) + ├── errors: (1 error) + │ └── @ VoidElementClosingTagError (location: (1:63)-(1:71)) + │ ├── message: "`input` is a void element and should not be used as a closing tag. Use `` or `` instead of ``." + │ ├── tag_name: "input" (location: (1:65)-(1:70)) + │ ├── expected: "" + │ └── found: "" + │ + ├── tag_opening: "" (location: (1:70)-(1:71)) \ No newline at end of file diff --git a/test/snapshots/parser/attributes_test/test_0040_Vue-style_directive_attribute_without_value_14a36e2ed468092336d9f6080e939190.txt b/test/snapshots/parser/attributes_test/test_0040_Vue-style_directive_attribute_without_value_14a36e2ed468092336d9f6080e939190.txt new file mode 100644 index 000000000..b5437392d --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0040_Vue-style_directive_attribute_without_value_14a36e2ed468092336d9f6080e939190.txt @@ -0,0 +1,33 @@ +@ DocumentNode (location: (1:0)-(1:21)) +└── children: (1 item) + └── @ HTMLElementNode (location: (1:0)-(1:21)) + ├── open_tag: + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:15)) + │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── tag_closing: ">" (location: (1:14)-(1:15)) + │ ├── children: (1 item) + │ │ └── @ HTMLAttributeNode (location: (1:5)-(1:14)) + │ │ ├── name: + │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:14)) + │ │ │ └── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:5)-(1:14)) + │ │ │ └── content: ":disabled" + │ │ │ + │ │ │ + │ │ ├── equals: ∅ + │ │ └── value: ∅ + │ │ + │ └── is_void: false + │ + ├── tag_name: "div" (location: (1:1)-(1:4)) + ├── body: [] + ├── close_tag: + │ └── @ HTMLCloseTagNode (location: (1:15)-(1:21)) + │ ├── tag_opening: "" (location: (1:20)-(1:21)) + │ + ├── is_void: false + └── source: "HTML" \ No newline at end of file diff --git a/test/snapshots/parser/attributes_test/test_0041_Mixed_Vue_directives_and_regular_attributes_355d0da3aae174783058e2ccec41ac05.txt b/test/snapshots/parser/attributes_test/test_0041_Mixed_Vue_directives_and_regular_attributes_355d0da3aae174783058e2ccec41ac05.txt new file mode 100644 index 000000000..adf1c8342 --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0041_Mixed_Vue_directives_and_regular_attributes_355d0da3aae174783058e2ccec41ac05.txt @@ -0,0 +1,82 @@ +@ DocumentNode (location: (1:0)-(1:61)) +└── children: (1 item) + └── @ HTMLElementNode (location: (1:0)-(1:61)) + ├── open_tag: + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:55)) + │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── tag_closing: ">" (location: (1:54)-(1:55)) + │ ├── children: (3 items) + │ │ ├── @ HTMLAttributeNode (location: (1:5)-(1:13)) + │ │ │ ├── name: + │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:7)) + │ │ │ │ └── children: (1 item) + │ │ │ │ └── @ LiteralNode (location: (1:5)-(1:7)) + │ │ │ │ └── content: "id" + │ │ │ │ + │ │ │ │ + │ │ │ ├── equals: "=" (location: (1:7)-(1:8)) + │ │ │ └── value: + │ │ │ └── @ HTMLAttributeValueNode (location: (1:8)-(1:13)) + │ │ │ ├── open_quote: """ (location: (1:8)-(1:9)) + │ │ │ ├── children: (1 item) + │ │ │ │ └── @ LiteralNode (location: (1:9)-(1:12)) + │ │ │ │ └── content: "app" + │ │ │ │ + │ │ │ ├── close_quote: """ (location: (1:12)-(1:13)) + │ │ │ └── quoted: true + │ │ │ + │ │ │ + │ │ ├── @ HTMLAttributeNode (location: (1:14)-(1:35)) + │ │ │ ├── name: + │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:14)-(1:20)) + │ │ │ │ └── children: (1 item) + │ │ │ │ └── @ LiteralNode (location: (1:14)-(1:20)) + │ │ │ │ └── content: ":class" + │ │ │ │ + │ │ │ │ + │ │ │ ├── equals: "=" (location: (1:20)-(1:21)) + │ │ │ └── value: + │ │ │ └── @ HTMLAttributeValueNode (location: (1:21)-(1:35)) + │ │ │ ├── open_quote: """ (location: (1:21)-(1:22)) + │ │ │ ├── children: (1 item) + │ │ │ │ └── @ LiteralNode (location: (1:22)-(1:34)) + │ │ │ │ └── content: "dynamicClass" + │ │ │ │ + │ │ │ ├── close_quote: """ (location: (1:34)-(1:35)) + │ │ │ └── quoted: true + │ │ │ + │ │ │ + │ │ └── @ HTMLAttributeNode (location: (1:36)-(1:54)) + │ │ ├── name: + │ │ │ └── @ HTMLAttributeNameNode (location: (1:36)-(1:45)) + │ │ │ └── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:36)-(1:45)) + │ │ │ └── content: "data-test" + │ │ │ + │ │ │ + │ │ ├── equals: "=" (location: (1:45)-(1:46)) + │ │ └── value: + │ │ └── @ HTMLAttributeValueNode (location: (1:46)-(1:54)) + │ │ ├── open_quote: """ (location: (1:46)-(1:47)) + │ │ ├── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:47)-(1:53)) + │ │ │ └── content: "static" + │ │ │ + │ │ ├── close_quote: """ (location: (1:53)-(1:54)) + │ │ └── quoted: true + │ │ + │ │ + │ └── is_void: false + │ + ├── tag_name: "div" (location: (1:1)-(1:4)) + ├── body: [] + ├── close_tag: + │ └── @ HTMLCloseTagNode (location: (1:55)-(1:61)) + │ ├── tag_opening: "" (location: (1:60)-(1:61)) + │ + ├── is_void: false + └── source: "HTML" \ No newline at end of file diff --git a/test/snapshots/parser/attributes_test/test_0042_Standalone_colon_with_space_is_invalid_c037b25064b31d22c6c195361999c5b8.txt b/test/snapshots/parser/attributes_test/test_0042_Standalone_colon_with_space_is_invalid_c037b25064b31d22c6c195361999c5b8.txt new file mode 100644 index 000000000..df076ee3a --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0042_Standalone_colon_with_space_is_invalid_c037b25064b31d22c6c195361999c5b8.txt @@ -0,0 +1,49 @@ +@ DocumentNode (location: (1:0)-(1:27)) +└── children: (1 item) + └── @ HTMLElementNode (location: (1:0)-(1:27)) + ├── open_tag: + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:21)) + │ ├── errors: (1 error) + │ │ └── @ UnexpectedError (location: (1:5)-(1:6)) + │ │ ├── message: "Unexpected Token. Expected: `TOKEN_IDENTIFIER, TOKEN_AT, TOKEN_ERB_START,TOKEN_WHITESPACE, or TOKEN_NEWLINE`, found: `TOKEN_COLON`." + │ │ ├── description: "Unexpected Token" + │ │ ├── expected: "TOKEN_IDENTIFIER, TOKEN_AT, TOKEN_ERB_START,TOKEN_WHITESPACE, or TOKEN_NEWLINE" + │ │ └── found: "TOKEN_COLON" + │ │ + │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── tag_closing: ">" (location: (1:20)-(1:21)) + │ ├── children: (1 item) + │ │ └── @ HTMLAttributeNode (location: (1:7)-(1:20)) + │ │ ├── name: + │ │ │ └── @ HTMLAttributeNameNode (location: (1:7)-(1:12)) + │ │ │ └── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:7)-(1:12)) + │ │ │ └── content: "class" + │ │ │ + │ │ │ + │ │ ├── equals: "=" (location: (1:12)-(1:13)) + │ │ └── value: + │ │ └── @ HTMLAttributeValueNode (location: (1:13)-(1:20)) + │ │ ├── open_quote: """ (location: (1:13)-(1:14)) + │ │ ├── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:14)-(1:19)) + │ │ │ └── content: "hello" + │ │ │ + │ │ ├── close_quote: """ (location: (1:19)-(1:20)) + │ │ └── quoted: true + │ │ + │ │ + │ └── is_void: false + │ + ├── tag_name: "div" (location: (1:1)-(1:4)) + ├── body: [] + ├── close_tag: + │ └── @ HTMLCloseTagNode (location: (1:21)-(1:27)) + │ ├── tag_opening: "" (location: (1:26)-(1:27)) + │ + ├── is_void: false + └── source: "HTML" \ No newline at end of file diff --git a/test/snapshots/parser/attributes_test/test_0043_Colon_immediately_followed_by_attribute_name_is_valid_e30b590c384b162d5019345f8083bfdb.txt b/test/snapshots/parser/attributes_test/test_0043_Colon_immediately_followed_by_attribute_name_is_valid_e30b590c384b162d5019345f8083bfdb.txt new file mode 100644 index 000000000..6913212c8 --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0043_Colon_immediately_followed_by_attribute_name_is_valid_e30b590c384b162d5019345f8083bfdb.txt @@ -0,0 +1,42 @@ +@ DocumentNode (location: (1:0)-(1:26)) +└── children: (1 item) + └── @ HTMLElementNode (location: (1:0)-(1:26)) + ├── open_tag: + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:20)) + │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── tag_closing: ">" (location: (1:19)-(1:20)) + │ ├── children: (1 item) + │ │ └── @ HTMLAttributeNode (location: (1:5)-(1:19)) + │ │ ├── name: + │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:11)) + │ │ │ └── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:5)-(1:11)) + │ │ │ └── content: ":class" + │ │ │ + │ │ │ + │ │ ├── equals: "=" (location: (1:11)-(1:12)) + │ │ └── value: + │ │ └── @ HTMLAttributeValueNode (location: (1:12)-(1:19)) + │ │ ├── open_quote: """ (location: (1:12)-(1:13)) + │ │ ├── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:13)-(1:18)) + │ │ │ └── content: "hello" + │ │ │ + │ │ ├── close_quote: """ (location: (1:18)-(1:19)) + │ │ └── quoted: true + │ │ + │ │ + │ └── is_void: false + │ + ├── tag_name: "div" (location: (1:1)-(1:4)) + ├── body: [] + ├── close_tag: + │ └── @ HTMLCloseTagNode (location: (1:20)-(1:26)) + │ ├── tag_opening: "" (location: (1:25)-(1:26)) + │ + ├── is_void: false + └── source: "HTML" \ No newline at end of file diff --git a/test/snapshots/parser/attributes_test/test_0044_Double_colon_is_invalid_f2b2354b82896dec0458b506ae56eb58.txt b/test/snapshots/parser/attributes_test/test_0044_Double_colon_is_invalid_f2b2354b82896dec0458b506ae56eb58.txt new file mode 100644 index 000000000..f0a1cedd0 --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0044_Double_colon_is_invalid_f2b2354b82896dec0458b506ae56eb58.txt @@ -0,0 +1,49 @@ +@ DocumentNode (location: (1:0)-(1:27)) +└── children: (1 item) + └── @ HTMLElementNode (location: (1:0)-(1:27)) + ├── open_tag: + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:21)) + │ ├── errors: (1 error) + │ │ └── @ UnexpectedError (location: (1:5)-(1:6)) + │ │ ├── message: "Unexpected Token. Expected: `TOKEN_IDENTIFIER, TOKEN_AT, TOKEN_ERB_START,TOKEN_WHITESPACE, or TOKEN_NEWLINE`, found: `TOKEN_COLON`." + │ │ ├── description: "Unexpected Token" + │ │ ├── expected: "TOKEN_IDENTIFIER, TOKEN_AT, TOKEN_ERB_START,TOKEN_WHITESPACE, or TOKEN_NEWLINE" + │ │ └── found: "TOKEN_COLON" + │ │ + │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── tag_closing: ">" (location: (1:20)-(1:21)) + │ ├── children: (1 item) + │ │ └── @ HTMLAttributeNode (location: (1:6)-(1:20)) + │ │ ├── name: + │ │ │ └── @ HTMLAttributeNameNode (location: (1:6)-(1:12)) + │ │ │ └── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:6)-(1:12)) + │ │ │ └── content: ":value" + │ │ │ + │ │ │ + │ │ ├── equals: "=" (location: (1:12)-(1:13)) + │ │ └── value: + │ │ └── @ HTMLAttributeValueNode (location: (1:13)-(1:20)) + │ │ ├── open_quote: """ (location: (1:13)-(1:14)) + │ │ ├── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:14)-(1:19)) + │ │ │ └── content: "hello" + │ │ │ + │ │ ├── close_quote: """ (location: (1:19)-(1:20)) + │ │ └── quoted: true + │ │ + │ │ + │ └── is_void: false + │ + ├── tag_name: "div" (location: (1:1)-(1:4)) + ├── body: [] + ├── close_tag: + │ └── @ HTMLCloseTagNode (location: (1:21)-(1:27)) + │ ├── tag_opening: "" (location: (1:26)-(1:27)) + │ + ├── is_void: false + └── source: "HTML" \ No newline at end of file diff --git a/test/snapshots/parser/attributes_test/test_0045_Vue_directive_with_namespace-like_syntax_e3d2d0afe1a0d7a4f71d0831ed0a9306.txt b/test/snapshots/parser/attributes_test/test_0045_Vue_directive_with_namespace-like_syntax_e3d2d0afe1a0d7a4f71d0831ed0a9306.txt new file mode 100644 index 000000000..0acd8fc4d --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0045_Vue_directive_with_namespace-like_syntax_e3d2d0afe1a0d7a4f71d0831ed0a9306.txt @@ -0,0 +1,42 @@ +@ DocumentNode (location: (1:0)-(1:27)) +└── children: (1 item) + └── @ HTMLElementNode (location: (1:0)-(1:27)) + ├── open_tag: + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:21)) + │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── tag_closing: ">" (location: (1:20)-(1:21)) + │ ├── children: (1 item) + │ │ └── @ HTMLAttributeNode (location: (1:5)-(1:20)) + │ │ ├── name: + │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:13)) + │ │ │ └── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:5)-(1:13)) + │ │ │ └── content: ":v-model" + │ │ │ + │ │ │ + │ │ ├── equals: "=" (location: (1:13)-(1:14)) + │ │ └── value: + │ │ └── @ HTMLAttributeValueNode (location: (1:14)-(1:20)) + │ │ ├── open_quote: """ (location: (1:14)-(1:15)) + │ │ ├── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:15)-(1:19)) + │ │ │ └── content: "user" + │ │ │ + │ │ ├── close_quote: """ (location: (1:19)-(1:20)) + │ │ └── quoted: true + │ │ + │ │ + │ └── is_void: false + │ + ├── tag_name: "div" (location: (1:1)-(1:4)) + ├── body: [] + ├── close_tag: + │ └── @ HTMLCloseTagNode (location: (1:21)-(1:27)) + │ ├── tag_opening: "" (location: (1:26)-(1:27)) + │ + ├── is_void: false + └── source: "HTML" \ No newline at end of file From bda6fd15ca2cfc4faaa07050392970a080958991 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sun, 14 Sep 2025 23:41:54 +0300 Subject: [PATCH 05/34] `v0.7.1` --- Gemfile.lock | 2 +- docs/package.json | 6 +- javascript/packages/browser/package.json | 4 +- .../packages/browser/test/browser.test.ts | 2 +- javascript/packages/core/package.json | 2 +- javascript/packages/dev-tools/package.json | 4 +- javascript/packages/formatter/package.json | 6 +- .../herb-language-server/package.json | 4 +- javascript/packages/highlighter/package.json | 6 +- .../packages/language-server/package.json | 8 +-- javascript/packages/linter/README.md | 4 +- javascript/packages/linter/package.json | 10 ++-- .../test/__snapshots__/cli.test.ts.snap | 58 +++++++++---------- javascript/packages/node-wasm/package.json | 4 +- .../packages/node-wasm/test/node-wasm.test.ts | 2 +- javascript/packages/node/package.json | 4 +- javascript/packages/node/test/node.test.ts | 2 +- javascript/packages/printer/package.json | 4 +- .../packages/stimulus-lint/package.json | 8 +-- .../tailwind-class-sorter/package.json | 2 +- javascript/packages/vscode/package.json | 8 +-- lib/herb/version.rb | 2 +- playground/package.json | 6 +- src/include/version.h | 2 +- test/c/test_herb.c | 2 +- test/herb_test.rb | 2 +- 26 files changed, 82 insertions(+), 82 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9c6dc596c..3d418004a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,7 +17,7 @@ GIT PATH remote: . specs: - herb (0.7.0) + herb (0.7.1) GEM remote: https://rubygems.org/ diff --git a/docs/package.json b/docs/package.json index 7ea1b8c66..026c8fd36 100644 --- a/docs/package.json +++ b/docs/package.json @@ -19,9 +19,9 @@ "fetch:contributors": "mkdir -p .vitepress/data/ && gh api -X get https://api.github.com/repos/marcoroth/herb/contributors > .vitepress/data/contributors.json" }, "dependencies": { - "@herb-tools/browser": "0.7.0", - "@herb-tools/core": "0.7.0", - "@herb-tools/node": "0.7.0" + "@herb-tools/browser": "0.7.1", + "@herb-tools/core": "0.7.1", + "@herb-tools/node": "0.7.1" }, "devDependencies": { "@shikijs/vitepress-twoslash": "^3.4.2", diff --git a/javascript/packages/browser/package.json b/javascript/packages/browser/package.json index b8f2f178a..fbfed9744 100644 --- a/javascript/packages/browser/package.json +++ b/javascript/packages/browser/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/browser", - "version": "0.7.0", + "version": "0.7.1", "description": "WebAssembly-based HTML-aware ERB parser for browsers.", "type": "module", "license": "MIT", @@ -34,7 +34,7 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.0" + "@herb-tools/core": "0.7.1" }, "files": [ "package.json", diff --git a/javascript/packages/browser/test/browser.test.ts b/javascript/packages/browser/test/browser.test.ts index 6fb22384e..17338ff46 100644 --- a/javascript/packages/browser/test/browser.test.ts +++ b/javascript/packages/browser/test/browser.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/browser", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/browser@0.7.0, @herb-tools/core@0.7.0, libprism@1.5.1, libherb@0.7.0 (WebAssembly)") + expect(version).toBe("@herb-tools/browser@0.7.1, @herb-tools/core@0.7.1, libprism@1.5.1, libherb@0.7.1 (WebAssembly)") }) test("parse() can process a simple template", async () => { diff --git a/javascript/packages/core/package.json b/javascript/packages/core/package.json index d88f33727..584b138c6 100644 --- a/javascript/packages/core/package.json +++ b/javascript/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/core", - "version": "0.7.0", + "version": "0.7.1", "description": "Core module exporting shared interfaces, AST node definitions, and common utilities for Herb", "type": "module", "license": "MIT", diff --git a/javascript/packages/dev-tools/package.json b/javascript/packages/dev-tools/package.json index 3b5db7794..777a3e6ef 100644 --- a/javascript/packages/dev-tools/package.json +++ b/javascript/packages/dev-tools/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/dev-tools", - "version": "0.7.0", + "version": "0.7.1", "description": "Development tools for visual debugging in HTML+ERB templates", "type": "module", "license": "MIT", @@ -30,7 +30,7 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.0" + "@herb-tools/core": "0.7.1" }, "files": [ "package.json", diff --git a/javascript/packages/formatter/package.json b/javascript/packages/formatter/package.json index 72825ed7c..0410310f7 100644 --- a/javascript/packages/formatter/package.json +++ b/javascript/packages/formatter/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/formatter", - "version": "0.7.0", + "version": "0.7.1", "description": "Auto-formatter for HTML+ERB templates with intelligent indentation, line wrapping, and ERB-aware pretty-printing.", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -35,8 +35,8 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.0", - "@herb-tools/printer": "0.7.0" + "@herb-tools/core": "0.7.1", + "@herb-tools/printer": "0.7.1" }, "devDependencies": { "glob": "^11.0.3" diff --git a/javascript/packages/herb-language-server/package.json b/javascript/packages/herb-language-server/package.json index fe35c8037..e823118e6 100644 --- a/javascript/packages/herb-language-server/package.json +++ b/javascript/packages/herb-language-server/package.json @@ -1,7 +1,7 @@ { "name": "herb-language-server", "description": "Placeholder package to reserve the herb-language-server name on NPM; use @herb-tools/language-server instead.", - "version": "0.7.0", + "version": "0.7.1", "author": "Marco Roth", "license": "MIT", "engines": { @@ -45,6 +45,6 @@ "dist/" ], "dependencies": { - "@herb-tools/language-server": "0.7.0" + "@herb-tools/language-server": "0.7.1" } } diff --git a/javascript/packages/highlighter/package.json b/javascript/packages/highlighter/package.json index 6041a941e..af8ee4620 100644 --- a/javascript/packages/highlighter/package.json +++ b/javascript/packages/highlighter/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/highlighter", - "version": "0.7.0", + "version": "0.7.1", "description": "Syntax highlighter and diagnostic renderer for HTML+ERB templates.", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -35,8 +35,8 @@ "prepublishOnly": "yarn clean && yarn build && yarn test" }, "dependencies": { - "@herb-tools/core": "0.7.0", - "@herb-tools/node-wasm": "0.7.0", + "@herb-tools/core": "0.7.1", + "@herb-tools/node-wasm": "0.7.1", "glob": "^11.0.3" }, "files": [ diff --git a/javascript/packages/language-server/package.json b/javascript/packages/language-server/package.json index c4c108c7f..53da675ba 100644 --- a/javascript/packages/language-server/package.json +++ b/javascript/packages/language-server/package.json @@ -1,7 +1,7 @@ { "name": "@herb-tools/language-server", "description": "Herb HTML+ERB Language Tools and Language Server Protocol integration.", - "version": "0.7.0", + "version": "0.7.1", "author": "Marco Roth", "license": "MIT", "engines": { @@ -45,9 +45,9 @@ "dist/" ], "dependencies": { - "@herb-tools/formatter": "0.7.0", - "@herb-tools/linter": "0.7.0", - "@herb-tools/node-wasm": "0.7.0", + "@herb-tools/formatter": "0.7.1", + "@herb-tools/linter": "0.7.1", + "@herb-tools/node-wasm": "0.7.1", "dedent": "^1.6.0", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.12" diff --git a/javascript/packages/linter/README.md b/javascript/packages/linter/README.md index 435e07b99..e0272696a 100644 --- a/javascript/packages/linter/README.md +++ b/javascript/packages/linter/README.md @@ -184,7 +184,7 @@ npx @herb-tools/linter --format=simple --github **Example: `--github` (GitHub annotations + detailed format)** ``` -::error file=template.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.0::Missing required `alt` attribute on `` tag [html-img-require-alt]%0A%0A%0Atemplate.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A +::error file=template.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required `alt` attribute on `` tag [html-img-require-alt]%0A%0A%0Atemplate.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A [error] Missing required `alt` attribute on `` tag [html-img-require-alt] @@ -199,7 +199,7 @@ template.html.erb:3:3 **Example: `--format=simple --github` (GitHub annotations + simple format)** ``` -::error file=template.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.0::Missing required `alt` attribute on `` tag [html-img-require-alt]%0A%0A%0Atemplate.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A +::error file=template.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required `alt` attribute on `` tag [html-img-require-alt]%0A%0A%0Atemplate.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A template.html.erb: 3:3 ✗ Missing required `alt` attribute on `` tag [html-img-require-alt] diff --git a/javascript/packages/linter/package.json b/javascript/packages/linter/package.json index be14e28bf..4ce916335 100644 --- a/javascript/packages/linter/package.json +++ b/javascript/packages/linter/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/linter", - "version": "0.7.0", + "version": "0.7.1", "description": "HTML+ERB linter for validating HTML structure and enforcing best practices", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -39,10 +39,10 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.0", - "@herb-tools/highlighter": "0.7.0", - "@herb-tools/node-wasm": "0.7.0", - "@herb-tools/printer": "0.7.0", + "@herb-tools/core": "0.7.1", + "@herb-tools/highlighter": "0.7.1", + "@herb-tools/node-wasm": "0.7.1", + "@herb-tools/printer": "0.7.1", "glob": "^11.0.3" }, "files": [ diff --git a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap index 1baad2c63..140dc6680 100644 --- a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap +++ b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap @@ -1,11 +1,11 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`CLI Output Formatting > GitHub Actions format escapes special characters in messages 1`] = ` -"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.0::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A +"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.0::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.0::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A [error] Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. (html-img-require-alt) @@ -55,7 +55,7 @@ test/fixtures/test-file-with-errors.html.erb:2:22 `; exports[`CLI Output Formatting > GitHub Actions format includes rule codes 1`] = ` -"::error file=test/fixtures/no-trailing-newline.html.erb,line=1,col=29,title=erb-requires-trailing-newline • @herb-tools/linter@0.7.0::File must end with trailing newline [erb-requires-trailing-newline]%0A%0A%0Atest/fixtures/no-trailing-newline.html.erb:1:29%0A%0A → 1 │
No trailing newline
%0A │ ~%0A +"::error file=test/fixtures/no-trailing-newline.html.erb,line=1,col=29,title=erb-requires-trailing-newline • @herb-tools/linter@0.7.1::File must end with trailing newline [erb-requires-trailing-newline]%0A%0A%0Atest/fixtures/no-trailing-newline.html.erb:1:29%0A%0A → 1 │
No trailing newline
%0A │ ~%0A [error] File must end with trailing newline (erb-requires-trailing-newline) @@ -93,10 +93,10 @@ test/fixtures/multiple-rule-offenses.html.erb:5:3 test/fixtures/multiple-rule-offenses.html.erb:10:1 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -107,10 +107,10 @@ test/fixtures/multiple-rule-offenses.html.erb:10:1 test/fixtures/multiple-rule-offenses.html.erb:10:4 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -121,7 +121,7 @@ test/fixtures/multiple-rule-offenses.html.erb:10:4 test/fixtures/multiple-rule-offenses.html.erb:3:20 1 │ - 2 │ + 2 │ → 3 │
│ ~~ 4 │ @@ -135,7 +135,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:20 test/fixtures/multiple-rule-offenses.html.erb:3:8 1 │ - 2 │ + 2 │ → 3 │
│ ~~~~~ 4 │ @@ -149,7 +149,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:8 test/fixtures/multiple-rule-offenses.html.erb:3:34 1 │ - 2 │ + 2 │ → 3 │
│ ~~~ 4 │ @@ -162,7 +162,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:34 test/fixtures/multiple-rule-offenses.html.erb:4:3 - 2 │ + 2 │ 3 │
→ 4 │ │ ~~~ @@ -191,7 +191,7 @@ test/fixtures/multiple-rule-offenses.html.erb:5:14 test/fixtures/multiple-rule-offenses.html.erb:3:14 1 │ - 2 │ + 2 │ → 3 │
│ ~~~~~ 4 │ @@ -233,10 +233,10 @@ test/fixtures/multiple-rule-offenses.html.erb:5:14 test/fixtures/multiple-rule-offenses.html.erb:8:0 6 │
- 7 │ + 7 │ → 8 │

│ ~~~~~~~~~ - 9 │ + 9 │ 10 │ Nested @@ -247,10 +247,10 @@ test/fixtures/multiple-rule-offenses.html.erb:8:0 test/fixtures/multiple-rule-offenses.html.erb:10:4 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -260,7 +260,7 @@ test/fixtures/multiple-rule-offenses.html.erb:10:4 test/fixtures/multiple-rule-offenses.html.erb:4:2 - 2 │ + 2 │ 3 │
→ 4 │ │ ~~~~~~~ @@ -341,7 +341,7 @@ test/fixtures/few-rule-offenses.html.erb:3:3 test/fixtures/few-rule-offenses.html.erb:9:5 - 7 │ + 7 │ 8 │
→ 9 │
│ ~~~~~~~~~~~~~~ @@ -355,10 +355,10 @@ test/fixtures/few-rule-offenses.html.erb:9:5 test/fixtures/few-rule-offenses.html.erb:6:0 4 │
- 5 │ + 5 │ → 6 │

│ ~~~~~~~~~ - 7 │ + 7 │ 8 │
@@ -389,9 +389,9 @@ test/fixtures/few-rule-offenses.html.erb:3:16 `; exports[`CLI Output Formatting > formats GitHub Actions output correctly for bad file 1`] = ` -"::error file=test/fixtures/bad-file.html.erb,line=1,col=1,title=html-tag-name-lowercase • @herb-tools/linter@0.7.0::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/bad-file.html.erb:1:1%0A%0A → 1 │ Bad file%0A │ ~~~~%0A 2 │%0A +"::error file=test/fixtures/bad-file.html.erb,line=1,col=1,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/bad-file.html.erb:1:1%0A%0A → 1 │ Bad file%0A │ ~~~~%0A 2 │%0A -::error file=test/fixtures/bad-file.html.erb,line=1,col=16,title=html-tag-name-lowercase • @herb-tools/linter@0.7.0::Closing tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/bad-file.html.erb:1:16%0A%0A → 1 │ Bad file%0A │ ~~~~%0A 2 │%0A +::error file=test/fixtures/bad-file.html.erb,line=1,col=16,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Closing tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/bad-file.html.erb:1:16%0A%0A → 1 │ Bad file%0A │ ~~~~%0A 2 │%0A [error] Opening tag name \`\` should be lowercase. Use \`\` instead. (html-tag-name-lowercase) @@ -431,11 +431,11 @@ exports[`CLI Output Formatting > formats GitHub Actions output correctly for cle `; exports[`CLI Output Formatting > formats GitHub Actions output correctly for file with errors 1`] = ` -"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.0::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A +"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.0::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.0::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A [error] Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. (html-img-require-alt) @@ -773,11 +773,11 @@ test/fixtures/bad-file.html.erb:1:16 `; exports[`CLI Output Formatting > uses GitHub Actions format by default when GITHUB_ACTIONS is true 1`] = ` -"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.0::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A +"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.0::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.0::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A [error] Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. (html-img-require-alt) diff --git a/javascript/packages/node-wasm/package.json b/javascript/packages/node-wasm/package.json index 8691023f0..469dda9cb 100644 --- a/javascript/packages/node-wasm/package.json +++ b/javascript/packages/node-wasm/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/node-wasm", - "version": "0.7.0", + "version": "0.7.1", "description": "WebAssembly-based HTML-aware ERB parser for Node.js.", "type": "module", "license": "MIT", @@ -36,7 +36,7 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.0" + "@herb-tools/core": "0.7.1" }, "files": [ "package.json", diff --git a/javascript/packages/node-wasm/test/node-wasm.test.ts b/javascript/packages/node-wasm/test/node-wasm.test.ts index 343bd2989..4ec932eca 100644 --- a/javascript/packages/node-wasm/test/node-wasm.test.ts +++ b/javascript/packages/node-wasm/test/node-wasm.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/node-wasm", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/node-wasm@0.7.0, @herb-tools/core@0.7.0, libprism@1.5.1, libherb@0.7.0 (WebAssembly)") + expect(version).toBe("@herb-tools/node-wasm@0.7.1, @herb-tools/core@0.7.1, libprism@1.5.1, libherb@0.7.1 (WebAssembly)") }) test("parse() can process a simple template", async () => { diff --git a/javascript/packages/node/package.json b/javascript/packages/node/package.json index 561b2bb03..afc87e92d 100644 --- a/javascript/packages/node/package.json +++ b/javascript/packages/node/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/node", - "version": "0.7.0", + "version": "0.7.1", "description": "Native Node.js addon for HTML-aware ERB parsing using Herb.", "type": "module", "license": "MIT", @@ -48,7 +48,7 @@ "host": "https://github.com/marcoroth/herb/releases/download/" }, "dependencies": { - "@herb-tools/core": "0.7.0", + "@herb-tools/core": "0.7.1", "@mapbox/node-pre-gyp": "^2.0.0", "node-addon-api": "^5.1.0", "node-pre-gyp-github": "^2.0.0" diff --git a/javascript/packages/node/test/node.test.ts b/javascript/packages/node/test/node.test.ts index 8a3108b1c..afdf4e378 100644 --- a/javascript/packages/node/test/node.test.ts +++ b/javascript/packages/node/test/node.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/node", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/node@0.7.0, @herb-tools/core@0.7.0, libprism@1.5.1, libherb@0.7.0 (Node.js C++ native extension)") + expect(version).toBe("@herb-tools/node@0.7.1, @herb-tools/core@0.7.1, libprism@1.5.1, libherb@0.7.1 (Node.js C++ native extension)") }) test("parse() can process a simple template", async () => { diff --git a/javascript/packages/printer/package.json b/javascript/packages/printer/package.json index 3227cff25..6caa021b3 100644 --- a/javascript/packages/printer/package.json +++ b/javascript/packages/printer/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/printer", - "version": "0.7.0", + "version": "0.7.1", "description": "AST printer infrastructure and lossless reconstruction tool for HTML+ERB templates", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -37,7 +37,7 @@ "prepublishOnly": "yarn clean && yarn build && yarn test" }, "dependencies": { - "@herb-tools/core": "0.7.0", + "@herb-tools/core": "0.7.1", "glob": "^10.3.10" }, "files": [ diff --git a/javascript/packages/stimulus-lint/package.json b/javascript/packages/stimulus-lint/package.json index 6d98ec547..6a2c273b6 100644 --- a/javascript/packages/stimulus-lint/package.json +++ b/javascript/packages/stimulus-lint/package.json @@ -34,10 +34,10 @@ "prepublishOnly": "yarn clean && yarn build && yarn test" }, "dependencies": { - "@herb-tools/linter": "0.7.0", - "@herb-tools/core": "0.7.0", - "@herb-tools/node-wasm": "0.7.0", - "@herb-tools/highlighter": "0.7.0", + "@herb-tools/linter": "0.7.1", + "@herb-tools/core": "0.7.1", + "@herb-tools/node-wasm": "0.7.1", + "@herb-tools/highlighter": "0.7.1", "stimulus-parser": "^0.3.0" }, "files": [ diff --git a/javascript/packages/tailwind-class-sorter/package.json b/javascript/packages/tailwind-class-sorter/package.json index c3e5a073f..c06d13fb6 100644 --- a/javascript/packages/tailwind-class-sorter/package.json +++ b/javascript/packages/tailwind-class-sorter/package.json @@ -2,7 +2,7 @@ "type": "module", "name": "@herb-tools/tailwind-class-sorter", "description": "Standalone Tailwind CSS class sorter with Prettier plugin compatibility, extracted from tailwindlabs/prettier-plugin-tailwindcss", - "version": "0.7.0", + "version": "0.7.1", "license": "MIT", "main": "./dist/tailwind-class-sorter.cjs", "module": "./dist/tailwind-class-sorter.esm.js", diff --git a/javascript/packages/vscode/package.json b/javascript/packages/vscode/package.json index f89abac2a..8ad57c695 100644 --- a/javascript/packages/vscode/package.json +++ b/javascript/packages/vscode/package.json @@ -2,7 +2,7 @@ "name": "herb-lsp", "displayName": "Herb LSP - HTML+ERB Language Tools", "description": "VS Code extension for connecting with the Herb Language Server and Language Tools for HTML+ERB files", - "version": "0.7.0", + "version": "0.7.1", "private": true, "license": "MIT", "pricing": "Free", @@ -239,9 +239,9 @@ "prepublishOnly": "yarn clean && yarn build && yarn test" }, "devDependencies": { - "@herb-tools/formatter": "0.7.0", - "@herb-tools/linter": "0.7.0", - "@herb-tools/node-wasm": "0.7.0", + "@herb-tools/formatter": "0.7.1", + "@herb-tools/linter": "0.7.1", + "@herb-tools/node-wasm": "0.7.1", "@types/node": "20.x", "@types/vscode": "^1.43.0", "@typescript-eslint/eslint-plugin": "^8.40.0", diff --git a/lib/herb/version.rb b/lib/herb/version.rb index 31bcd62bb..1e15669b2 100644 --- a/lib/herb/version.rb +++ b/lib/herb/version.rb @@ -2,5 +2,5 @@ # typed: true module Herb - VERSION = "0.7.0" + VERSION = "0.7.1" end diff --git a/playground/package.json b/playground/package.json index f0a852fa7..487bc54b5 100644 --- a/playground/package.json +++ b/playground/package.json @@ -19,9 +19,9 @@ }, "dependencies": { "@alenaksu/json-viewer": "^2.0.1", - "@herb-tools/browser": "0.7.0", - "@herb-tools/formatter": "0.7.0", - "@herb-tools/linter": "0.7.0", + "@herb-tools/browser": "0.7.1", + "@herb-tools/formatter": "0.7.1", + "@herb-tools/linter": "0.7.1", "@hotwired/stimulus": "^3.2.2", "dedent": "^1.6.0", "express": "^5.1.0", diff --git a/src/include/version.h b/src/include/version.h index 1d1cc252f..3ed766735 100644 --- a/src/include/version.h +++ b/src/include/version.h @@ -1,6 +1,6 @@ #ifndef HERB_VERSION_H #define HERB_VERSION_H -#define HERB_VERSION "0.7.0" +#define HERB_VERSION "0.7.1" #endif diff --git a/test/c/test_herb.c b/test/c/test_herb.c index 18a1111da..e5d4632a1 100644 --- a/test/c/test_herb.c +++ b/test/c/test_herb.c @@ -2,7 +2,7 @@ #include "../../src/include/herb.h" TEST(test_herb_version) - ck_assert_str_eq(herb_version(), "0.7.0"); + ck_assert_str_eq(herb_version(), "0.7.1"); END TCase *herb_tests(void) { diff --git a/test/herb_test.rb b/test/herb_test.rb index ce1965ca0..38fd9397d 100644 --- a/test/herb_test.rb +++ b/test/herb_test.rb @@ -4,6 +4,6 @@ class HerbTest < Minitest::Spec test "version" do - assert_equal "herb gem v0.7.0, libprism v1.5.1, libherb v0.7.0 (Ruby C native extension)", Herb.version + assert_equal "herb gem v0.7.1, libprism v1.5.1, libherb v0.7.1 (Ruby C native extension)", Herb.version end end From 1da3ca207e280832fe6f8c88d5ff97483affba37 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Sun, 14 Sep 2025 23:49:26 +0300 Subject: [PATCH 06/34] Update Snapshot and Stimulus Lint version --- .../test/__snapshots__/cli.test.ts.snap | 34 +++++++++---------- .../packages/stimulus-lint/package.json | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap index 140dc6680..103b947d0 100644 --- a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap +++ b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap @@ -93,10 +93,10 @@ test/fixtures/multiple-rule-offenses.html.erb:5:3 test/fixtures/multiple-rule-offenses.html.erb:10:1 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -107,10 +107,10 @@ test/fixtures/multiple-rule-offenses.html.erb:10:1 test/fixtures/multiple-rule-offenses.html.erb:10:4 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -121,7 +121,7 @@ test/fixtures/multiple-rule-offenses.html.erb:10:4 test/fixtures/multiple-rule-offenses.html.erb:3:20 1 │ - 2 │ + 2 │ → 3 │
│ ~~ 4 │ @@ -135,7 +135,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:20 test/fixtures/multiple-rule-offenses.html.erb:3:8 1 │ - 2 │ + 2 │ → 3 │
│ ~~~~~ 4 │ @@ -149,7 +149,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:8 test/fixtures/multiple-rule-offenses.html.erb:3:34 1 │ - 2 │ + 2 │ → 3 │
│ ~~~ 4 │ @@ -162,7 +162,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:34 test/fixtures/multiple-rule-offenses.html.erb:4:3 - 2 │ + 2 │ 3 │
→ 4 │ │ ~~~ @@ -191,7 +191,7 @@ test/fixtures/multiple-rule-offenses.html.erb:5:14 test/fixtures/multiple-rule-offenses.html.erb:3:14 1 │ - 2 │ + 2 │ → 3 │
│ ~~~~~ 4 │ @@ -233,10 +233,10 @@ test/fixtures/multiple-rule-offenses.html.erb:5:14 test/fixtures/multiple-rule-offenses.html.erb:8:0 6 │
- 7 │ + 7 │ → 8 │

│ ~~~~~~~~~ - 9 │ + 9 │ 10 │ Nested @@ -247,10 +247,10 @@ test/fixtures/multiple-rule-offenses.html.erb:8:0 test/fixtures/multiple-rule-offenses.html.erb:10:4 8 │

- 9 │ + 9 │ → 10 │ Nested │ ~ - 11 │ + 11 │ 12 │
@@ -260,7 +260,7 @@ test/fixtures/multiple-rule-offenses.html.erb:10:4 test/fixtures/multiple-rule-offenses.html.erb:4:2 - 2 │ + 2 │ 3 │
→ 4 │ │ ~~~~~~~ @@ -341,7 +341,7 @@ test/fixtures/few-rule-offenses.html.erb:3:3 test/fixtures/few-rule-offenses.html.erb:9:5 - 7 │ + 7 │ 8 │
→ 9 │
│ ~~~~~~~~~~~~~~ @@ -355,10 +355,10 @@ test/fixtures/few-rule-offenses.html.erb:9:5 test/fixtures/few-rule-offenses.html.erb:6:0 4 │
- 5 │ + 5 │ → 6 │

│ ~~~~~~~~~ - 7 │ + 7 │ 8 │
diff --git a/javascript/packages/stimulus-lint/package.json b/javascript/packages/stimulus-lint/package.json index 6a2c273b6..a55bde199 100644 --- a/javascript/packages/stimulus-lint/package.json +++ b/javascript/packages/stimulus-lint/package.json @@ -1,6 +1,6 @@ { "name": "stimulus-lint", - "version": "0.1.0", + "version": "0.1.1", "description": "Linting rules for Stimulus controllers and HTML+ERB view templates.", "license": "MIT", "homepage": "https://herb-tools.dev", From 7517bb0c7d1f03d106b5326fdb875ab6df7cacb1 Mon Sep 17 00:00:00 2001 From: Alessandro Rodi Date: Tue, 16 Sep 2025 14:53:37 +0200 Subject: [PATCH 07/34] Remove double HTML-escaping from error template (#487) I noticed a problem where the symptom was a wrong font used in the template. this is because the html was somehow escaped wrong. I removed the escape and everything seems to work just fine. CleanShot 2025-09-08 at 20 33 54@2x Co-authored-by: Marco Roth --- lib/herb/engine.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/herb/engine.rb b/lib/herb/engine.rb index 91bffe258..e48988d61 100644 --- a/lib/herb/engine.rb +++ b/lib/herb/engine.rb @@ -359,8 +359,7 @@ def add_parser_error_overlay(parser_errors, input) ) error_html = overlay_generator.generate_html - escaped_html = error_html.gsub("'", "\\'") - @validation_error_template = "" + @validation_error_template = "" end end end From 0982bcc7345dc79494485cd84631454e4df80518 Mon Sep 17 00:00:00 2001 From: Lucas Kuhn Date: Tue, 16 Sep 2025 10:45:39 -0300 Subject: [PATCH 08/34] Formatter: Add `--indent-width` and `--max-line-length` args to the CLI (#466) This allows calling `herb-format` with arguments for customizing width ( `--indent-width` ) and line length ( `--max-line-length`) The expected behavior is to use the json config, but allowing cli args opens up to some workarounds while we don't have all integrations (eg: Zed) --- javascript/packages/formatter/src/cli.ts | 81 ++++++++++++++++--- .../packages/formatter/test/cli.test.ts | 33 ++++++++ 2 files changed, 102 insertions(+), 12 deletions(-) diff --git a/javascript/packages/formatter/src/cli.ts b/javascript/packages/formatter/src/cli.ts index 3d6983ddb..5d88c1d28 100644 --- a/javascript/packages/formatter/src/cli.ts +++ b/javascript/packages/formatter/src/cli.ts @@ -5,6 +5,8 @@ import { join, resolve } from "path" import { Herb } from "@herb-tools/node-wasm" import { Formatter } from "./formatter.js" +import { parseArgs } from "util" +import { resolveFormatOptions } from "./options.js" import { name, version, dependencies } from "../package.json" @@ -21,9 +23,11 @@ export class CLI { glob pattern to match files, or '-' for stdin (omit to format all **/*.html.erb files in current directory) Options: - -c, --check check if files are formatted without modifying them - -h, --help show help - -v, --version show version + -c, --check check if files are formatted without modifying them + -h, --help show help + -v, --version show version + --indent-width number of spaces per indentation level (default: 2) + --max-line-length maximum line length before wrapping (default: 80) Examples: herb-format # Format all **/*.html.erb files in current directory @@ -35,22 +39,71 @@ export class CLI { herb-format "**/*.xml.erb" # Format all .xml.erb files using glob pattern herb-format --check # Check if all **/*.html.erb files are formatted herb-format --check templates/ # Check if all **/*.html.erb files in templates/ are formatted + herb-format --indent-width 4 # Format with 4-space indentation + herb-format --max-line-length 100 # Format with 100-character line limit cat template.html.erb | herb-format # Format from stdin to stdout ` - async run() { - const args = process.argv.slice(2) - - if (args.includes("--help") || args.includes("-h")) { + private parseArguments() { + const { values, positionals } = parseArgs({ + args: process.argv.slice(2), + options: { + help: { type: "boolean", short: "h" }, + version: { type: "boolean", short: "v" }, + check: { type: "boolean", short: "c" }, + "indent-width": { type: "string" }, + "max-line-length": { type: "string" } + }, + allowPositionals: true + }) + + if (values.help) { console.log(this.usage) - process.exit(0) } + let indentWidth: number | undefined + + if (values["indent-width"]) { + const parsed = parseInt(values["indent-width"], 10) + if (isNaN(parsed) || parsed < 1) { + console.error( + `Invalid indent-width: ${values["indent-width"]}. Must be a positive integer.`, + ) + process.exit(1) + } + indentWidth = parsed + } + + let maxLineLength: number | undefined + + if (values["max-line-length"]) { + const parsed = parseInt(values["max-line-length"], 10) + if (isNaN(parsed) || parsed < 1) { + console.error( + `Invalid max-line-length: ${values["max-line-length"]}. Must be a positive integer.`, + ) + process.exit(1) + } + maxLineLength = parsed + } + + return { + positionals, + isCheckMode: values.check, + isVersionMode: values.version, + indentWidth, + maxLineLength + } + } + + async run() { + const { positionals, isCheckMode, isVersionMode, indentWidth, maxLineLength } = this.parseArguments() + try { await Herb.load() - if (args.includes("--version") || args.includes("-v")) { + if (isVersionMode) { console.log("Versions:") console.log(` ${name}@${version}`) console.log(` @herb-tools/printer@${dependencies['@herb-tools/printer']}`) @@ -62,10 +115,14 @@ export class CLI { console.log("⚠️ Experimental Preview: The formatter is in early development. Please report any unexpected behavior or bugs to https://github.com/marcoroth/herb/issues/new?template=formatting-issue.md") console.log() - const formatter = new Formatter(Herb) - const isCheckMode = args.includes("--check") || args.includes("-c") + const formatOptions = resolveFormatOptions({ + indentWidth, + maxLineLength + }) + + const formatter = new Formatter(Herb, formatOptions) - const file = args.find(arg => !arg.startsWith("-")) + const file = positionals[0] if (!file && !process.stdin.isTTY) { if (isCheckMode) { diff --git a/javascript/packages/formatter/test/cli.test.ts b/javascript/packages/formatter/test/cli.test.ts index b8140ee09..5d4d3ed46 100644 --- a/javascript/packages/formatter/test/cli.test.ts +++ b/javascript/packages/formatter/test/cli.test.ts @@ -399,6 +399,39 @@ describe("CLI Binary", () => { expect(formattedLines.join('\n')).toBe('\n') }) + it("should show --indent-width option in help", async () => { + const result = await execBinary(["--help"]) + + expectExitCode(result, 0) + expect(result.stdout).toContain("herb-format --indent-width") + expect(result.stdout).toContain("number of spaces per indentation level") + }) + + it("should accept valid --indent-width", async () => { + const input = '
\n

Test

\n
' + const result = await execBinary(["--indent-width", "4"], input) + + expectExitCode(result, 0) + expect(result.stdout).toContain("

Test

") // 4 spaces instead of 2 + }) + + it("should show --max-line-length option in help", async () => { + const result = await execBinary(["--help"]) + + expectExitCode(result, 0) + expect(result.stdout).toContain("herb-format --max-line-length") + expect(result.stdout).toContain("maximum line length before wrapping") + }) + + it("should accept valid --max-line-length", async () => { + const input = '

Short text that wraps

' + const result = await execBinary(["--max-line-length", "20"], input) + + expectExitCode(result, 0) + expect(result.stdout).toContain("Short text that") + expect(result.stdout).toContain("wraps") + }) + describe("Glob Pattern Support", () => { beforeEach(async () => { await mkdir("test-fixtures", { recursive: true }) From 5cb2fcddb9a0e4f26b743d1892dd770db5bd2ab5 Mon Sep 17 00:00:00 2001 From: Juan Miguel Date: Tue, 16 Sep 2025 15:56:17 +0200 Subject: [PATCH 09/34] Add Cursor as available editor to link source files (#486) When opening a link on ReActionView there's no possibility to open the source code with Cursor, it's opening VSCode by default. By adding the editor here I can open cursor now. --- javascript/packages/dev-tools/src/herb-overlay.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/packages/dev-tools/src/herb-overlay.ts b/javascript/packages/dev-tools/src/herb-overlay.ts index 1657e0bf6..70aa8b5a4 100644 --- a/javascript/packages/dev-tools/src/herb-overlay.ts +++ b/javascript/packages/dev-tools/src/herb-overlay.ts @@ -928,6 +928,7 @@ export class HerbOverlay { const absolutePath = file.startsWith('/') ? file : (this.projectPath ? `${this.projectPath}/${file}` : file); const editors = [ + `cursor://file/${absolutePath}:${line}:${column}`, `vscode://file/${absolutePath}:${line}:${column}`, `subl://open?url=file://${absolutePath}&line=${line}&column=${column}`, `atom://core/open/file?filename=${absolutePath}&line=${line}&column=${column}`, From 361a090a233826aeb7dc351acda786421d2676ac Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Tue, 16 Sep 2025 17:06:18 +0300 Subject: [PATCH 10/34] Use `rb_utf8_str_new_cstr()` in Ruby C-Extension (#500) This pull request updates the Ruby C-Extension to use `rb_utf8_str_new_cstr()` over `rb_str_new_cstr()` when constructing Ruby Strings from the C `char[]`. This ensures we always have a UTF-8 string so we don't trigger a `Encoding::CompatibilityError (incompatible character encodings: BINARY (ASCII-8BIT) and UTF-8)` when concatenating strings. It looks like `rb_str_new_cstr()` sometimes produces an `UTF-8` string and sometimes an `ASCII-8BIT` string based on the content. Resolves https://github.com/marcoroth/herb/issues/492 Resolves https://github.com/marcoroth/reactionview/issues/4 --- examples/utf8.html.erb | 5 +++++ ext/herb/extension.c | 12 ++++++------ ext/herb/extension_helpers.c | 6 +++--- templates/ext/herb/error_helpers.c.erb | 8 ++++---- templates/ext/herb/nodes.c.erb | 6 +++--- test/engine/evaluation_test.rb | 12 ++++++++++++ ...tf8_handling_1a606908d02705253fec4859259e69e2.txt | 5 +++++ ..._compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt | 8 ++++++++ ...compilation_a705eb5ed83b4db368d7204baa136b36.txt} | 0 ...eaking_space_8df6fbcc43d31d99e5112eb009ed8a2d.txt | 2 +- ...ut_(2_bytes)_8419b71c87a225a2c70b50486fbee545.txt | 2 +- ...gn_(3_bytes)_bca53fde466a76b7bee3e18997e94a7a.txt | 2 +- ...ji_(4_bytes)_9a9854bb735591cd2296c7d2e7c70c96.txt | 2 +- ...8_characters_0a09d7ee1e23c509e5e6846c86823081.txt | 6 +++--- ...II_and_UTF-8_60791161b6a23965fd2c7c4f28b40ef7.txt | 2 +- ..._in_HTML_tag_23d7cee67799f39f80ff3c8c3f123876.txt | 2 +- ...ribute_value_33c8000ce11b738c064a2480a67cd966.txt | 4 ++-- ...code_symbols_56dca1fb5e06fa932b775ab821350f5d.txt | 10 +++++----- ...oji_sequence_20411a338175125c89c7b53b1a7171eb.txt | 8 ++++---- ...e_characters_65396ee4aad0b4f17aacd1c6112ee364.txt | 8 ++++---- ..._Arabic_text_9530db02d3c8217be00c1aa98ec51861.txt | 10 +++++----- ...ML_structure_2eedd7e4e1585b52553db2fcf70bdfb9.txt | 8 ++++---- ..._positioning_87772e0d3b85d8cab09a1c354d70b213.txt | 6 +++--- ...F-8_with_ERB_b6276e3bed3faa902628e7bd34d5d3d7.txt | 2 +- 24 files changed, 83 insertions(+), 53 deletions(-) create mode 100644 examples/utf8.html.erb create mode 100644 test/snapshots/engine/evaluation_test/test_0023_utf8_handling_1a606908d02705253fec4859259e69e2.txt create mode 100644 test/snapshots/engine/examples_compilation_test/test_0017_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt rename test/snapshots/engine/examples_compilation_test/{test_0017_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt => test_0018_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt} (100%) diff --git a/examples/utf8.html.erb b/examples/utf8.html.erb new file mode 100644 index 000000000..2e93cdb56 --- /dev/null +++ b/examples/utf8.html.erb @@ -0,0 +1,5 @@ +Sitename • Title + +<% @title = "Home" %> + +<%= [@title, "Sitename"].compact.join(" • ") %> diff --git a/ext/herb/extension.c b/ext/herb/extension.c index e6e569e5e..7f83a0090 100644 --- a/ext/herb/extension.c +++ b/ext/herb/extension.c @@ -50,7 +50,7 @@ static VALUE Herb_parse(int argc, VALUE* argv, VALUE self) { parser_options_T opts = { 0 }; if (!NIL_P(options)) { - VALUE track_whitespace = rb_hash_lookup(options, rb_str_new_cstr("track_whitespace")); + VALUE track_whitespace = rb_hash_lookup(options, rb_utf8_str_new_cstr("track_whitespace")); if (NIL_P(track_whitespace)) { track_whitespace = rb_hash_lookup(options, ID2SYM(rb_intern("track_whitespace"))); } if (!NIL_P(track_whitespace) && RTEST(track_whitespace)) { @@ -108,7 +108,7 @@ static VALUE Herb_extract_ruby(VALUE self, VALUE source) { herb_extract_ruby_to_buffer(string, &output); - VALUE result = rb_str_new_cstr(output.value); + VALUE result = rb_utf8_str_new_cstr(output.value); buffer_free(&output); return result; @@ -122,7 +122,7 @@ static VALUE Herb_extract_html(VALUE self, VALUE source) { herb_extract_html_to_buffer(string, &output); - VALUE result = rb_str_new_cstr(output.value); + VALUE result = rb_utf8_str_new_cstr(output.value); buffer_free(&output); return result; @@ -130,9 +130,9 @@ static VALUE Herb_extract_html(VALUE self, VALUE source) { static VALUE Herb_version(VALUE self) { VALUE gem_version = rb_const_get(self, rb_intern("VERSION")); - VALUE libherb_version = rb_str_new_cstr(herb_version()); - VALUE libprism_version = rb_str_new_cstr(herb_prism_version()); - VALUE format_string = rb_str_new_cstr("herb gem v%s, libprism v%s, libherb v%s (Ruby C native extension)"); + VALUE libherb_version = rb_utf8_str_new_cstr(herb_version()); + VALUE libprism_version = rb_utf8_str_new_cstr(herb_prism_version()); + VALUE format_string = rb_utf8_str_new_cstr("herb gem v%s, libprism v%s, libherb v%s (Ruby C native extension)"); return rb_funcall(rb_mKernel, rb_intern("sprintf"), 4, format_string, gem_version, libprism_version, libherb_version); } diff --git a/ext/herb/extension_helpers.c b/ext/herb/extension_helpers.c index 0d4814a95..875f34d1f 100644 --- a/ext/herb/extension_helpers.c +++ b/ext/herb/extension_helpers.c @@ -53,11 +53,11 @@ VALUE rb_range_from_c_struct(range_T* range) { VALUE rb_token_from_c_struct(token_T* token) { if (!token) { return Qnil; } - VALUE value = token->value ? rb_str_new_cstr(token->value) : Qnil; + VALUE value = token->value ? rb_utf8_str_new_cstr(token->value) : Qnil; VALUE range = rb_range_from_c_struct(token->range); VALUE location = rb_location_from_c_struct(token->location); - VALUE type = rb_str_new_cstr(token_type_to_string(token->type)); + VALUE type = rb_utf8_str_new_cstr(token_type_to_string(token->type)); VALUE args[4] = { value, range, location, type }; @@ -91,7 +91,7 @@ VALUE create_parse_result(AST_DOCUMENT_NODE_T* root, VALUE source) { VALUE read_file_to_ruby_string(const char* file_path) { char* source = herb_read_file(file_path); - VALUE source_value = rb_str_new_cstr(source); + VALUE source_value = rb_utf8_str_new_cstr(source); free(source); diff --git a/templates/ext/herb/error_helpers.c.erb b/templates/ext/herb/error_helpers.c.erb index 20b7f2734..5771a91eb 100644 --- a/templates/ext/herb/error_helpers.c.erb +++ b/templates/ext/herb/error_helpers.c.erb @@ -21,9 +21,9 @@ static VALUE rb_<%= error.human %>_from_c_struct(<%= error.struct_type %>* <%= e VALUE Error = rb_define_class_under(Errors, "Error", rb_cObject); VALUE <%= error.name %> = rb_define_class_under(Errors, "<%= error.name %>", Error); - VALUE type = rb_str_new_cstr(error_type_to_string(error)); + VALUE type = rb_utf8_str_new_cstr(error_type_to_string(error)); VALUE location = rb_location_from_c_struct(error->location); - VALUE message = rb_str_new_cstr(error->message); + VALUE message = rb_utf8_str_new_cstr(error->message); <%- error.fields.each do |field| -%> <%- case field -%> @@ -32,9 +32,9 @@ static VALUE rb_<%= error.human %>_from_c_struct(<%= error.struct_type %>* <%= e <%- when Herb::Template::TokenField -%> VALUE <%= error.human %>_<%= field.name %> = rb_token_from_c_struct(<%= error.human %>-><%= field.name %>); <%- when Herb::Template::TokenTypeField -%> - VALUE <%= error.human %>_<%= field.name %> = rb_str_new_cstr(token_type_to_string(<%= error.human %>-><%= field.name %>)); + VALUE <%= error.human %>_<%= field.name %> = rb_utf8_str_new_cstr(token_type_to_string(<%= error.human %>-><%= field.name %>)); <%- when Herb::Template::StringField -%> - VALUE <%= error.human %>_<%= field.name %> = rb_str_new_cstr(<%= error.human %>-><%= field.name %>); + VALUE <%= error.human %>_<%= field.name %> = rb_utf8_str_new_cstr(<%= error.human %>-><%= field.name %>); <%- else -%> /* <%= field.inspect %> */ VALUE <%= error.human %>_<%= field.name %> = Qnil; diff --git a/templates/ext/herb/nodes.c.erb b/templates/ext/herb/nodes.c.erb index f6ef0c6a8..5fd5d677f 100644 --- a/templates/ext/herb/nodes.c.erb +++ b/templates/ext/herb/nodes.c.erb @@ -22,14 +22,14 @@ static VALUE rb_<%= node.human %>_from_c_struct(<%= node.struct_type %>* <%= nod VALUE Node = rb_define_class_under(AST, "Node", rb_cObject); VALUE <%= node.name %> = rb_define_class_under(AST, "<%= node.name %>", Node); - VALUE type = rb_str_new_cstr(ast_node_type_to_string(node)); + VALUE type = rb_utf8_str_new_cstr(ast_node_type_to_string(node)); VALUE location = rb_location_from_c_struct(node->location); VALUE errors = rb_errors_array_from_c_array(node->errors); <%- node.fields.each do |field| -%> <%- case field -%> <%- when Herb::Template::StringField -%> - VALUE <%= node.human %>_<%= field.name %> = rb_str_new_cstr(<%= node.human %>-><%= field.name %>); + VALUE <%= node.human %>_<%= field.name %> = rb_utf8_str_new_cstr(<%= node.human %>-><%= field.name %>); <%- when Herb::Template::NodeField -%> VALUE <%= node.human %>_<%= field.name %> = rb_node_from_c_struct((AST_NODE_T*) <%= node.human %>-><%= field.name %>); <%- when Herb::Template::TokenField -%> @@ -39,7 +39,7 @@ static VALUE rb_<%= node.human %>_from_c_struct(<%= node.struct_type %>* <%= nod <%- when Herb::Template::ArrayField -%> VALUE <%= node.human %>_<%= field.name %> = rb_nodes_array_from_c_array(<%= node.human %>-><%= field.name %>); <%- when Herb::Template::ElementSourceField -%> - VALUE <%= node.human %>_<%= field.name %> = rb_str_new_cstr(element_source_to_string(<%= node.human %>-><%= field.name %>)); + VALUE <%= node.human %>_<%= field.name %> = rb_utf8_str_new_cstr(element_source_to_string(<%= node.human %>-><%= field.name %>)); <%- else -%> /* <%= field.inspect %> */ VALUE <%= node.human %>_<%= field.name %> = Qnil; diff --git a/test/engine/evaluation_test.rb b/test/engine/evaluation_test.rb index 712d7c29c..5aff27f4a 100644 --- a/test/engine/evaluation_test.rb +++ b/test/engine/evaluation_test.rb @@ -377,5 +377,17 @@ class EvaluationTest < Minitest::Spec posts: posts, }, { escape: false }) end + + test "utf8 handling" do + template = <<~ERB + Sitename • Title + + <% @title = "Home" %> + + <%= [@title, "Sitename"].compact.join(" • ") %> + ERB + + assert_evaluated_snapshot(template, {}, { escape: false }) + end end end diff --git a/test/snapshots/engine/evaluation_test/test_0023_utf8_handling_1a606908d02705253fec4859259e69e2.txt b/test/snapshots/engine/evaluation_test/test_0023_utf8_handling_1a606908d02705253fec4859259e69e2.txt new file mode 100644 index 000000000..84a768ce6 --- /dev/null +++ b/test/snapshots/engine/evaluation_test/test_0023_utf8_handling_1a606908d02705253fec4859259e69e2.txt @@ -0,0 +1,5 @@ +Sitename • Title + + + +Home • Sitename diff --git a/test/snapshots/engine/examples_compilation_test/test_0017_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt b/test/snapshots/engine/examples_compilation_test/test_0017_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt new file mode 100644 index 000000000..65f981961 --- /dev/null +++ b/test/snapshots/engine/examples_compilation_test/test_0017_utf8_compilation_45fa7aa654c0dc06d1a1b9504002dfba.txt @@ -0,0 +1,8 @@ +_buf = ::String.new; + _buf << 'Sitename • Title + +'.freeze; @title = "Home"; _buf << ' + +'.freeze; _buf << ([@title, "Sitename"].compact.join(" • ")).to_s; _buf << ' +'.freeze; +_buf.to_s diff --git a/test/snapshots/engine/examples_compilation_test/test_0017_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt b/test/snapshots/engine/examples_compilation_test/test_0018_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt similarity index 100% rename from test/snapshots/engine/examples_compilation_test/test_0017_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt rename to test/snapshots/engine/examples_compilation_test/test_0018_while_compilation_a705eb5ed83b4db368d7204baa136b36.txt diff --git a/test/snapshots/lexer/token_test/test_0004_non-breaking_space_8df6fbcc43d31d99e5112eb009ed8a2d.txt b/test/snapshots/lexer/token_test/test_0004_non-breaking_space_8df6fbcc43d31d99e5112eb009ed8a2d.txt index ab2f64163..ab30abe9b 100644 --- a/test/snapshots/lexer/token_test/test_0004_non-breaking_space_8df6fbcc43d31d99e5112eb009ed8a2d.txt +++ b/test/snapshots/lexer/token_test/test_0004_non-breaking_space_8df6fbcc43d31d99e5112eb009ed8a2d.txt @@ -1,2 +1,2 @@ -# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0001_single_UTF-8_character_-_a-umlaut_(2_bytes)_8419b71c87a225a2c70b50486fbee545.txt b/test/snapshots/lexer/utf8_test/test_0001_single_UTF-8_character_-_a-umlaut_(2_bytes)_8419b71c87a225a2c70b50486fbee545.txt index ee7fe39bb..53a55a696 100644 --- a/test/snapshots/lexer/utf8_test/test_0001_single_UTF-8_character_-_a-umlaut_(2_bytes)_8419b71c87a225a2c70b50486fbee545.txt +++ b/test/snapshots/lexer/utf8_test/test_0001_single_UTF-8_character_-_a-umlaut_(2_bytes)_8419b71c87a225a2c70b50486fbee545.txt @@ -1,2 +1,2 @@ -# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0002_single_UTF-8_character_-_euro_sign_(3_bytes)_bca53fde466a76b7bee3e18997e94a7a.txt b/test/snapshots/lexer/utf8_test/test_0002_single_UTF-8_character_-_euro_sign_(3_bytes)_bca53fde466a76b7bee3e18997e94a7a.txt index 779084b23..ffd9c14dd 100644 --- a/test/snapshots/lexer/utf8_test/test_0002_single_UTF-8_character_-_euro_sign_(3_bytes)_bca53fde466a76b7bee3e18997e94a7a.txt +++ b/test/snapshots/lexer/utf8_test/test_0002_single_UTF-8_character_-_euro_sign_(3_bytes)_bca53fde466a76b7bee3e18997e94a7a.txt @@ -1,2 +1,2 @@ -# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0003_single_UTF-8_character_-_emoji_(4_bytes)_9a9854bb735591cd2296c7d2e7c70c96.txt b/test/snapshots/lexer/utf8_test/test_0003_single_UTF-8_character_-_emoji_(4_bytes)_9a9854bb735591cd2296c7d2e7c70c96.txt index 32df1f5b9..4ff57c11c 100644 --- a/test/snapshots/lexer/utf8_test/test_0003_single_UTF-8_character_-_emoji_(4_bytes)_9a9854bb735591cd2296c7d2e7c70c96.txt +++ b/test/snapshots/lexer/utf8_test/test_0003_single_UTF-8_character_-_emoji_(4_bytes)_9a9854bb735591cd2296c7d2e7c70c96.txt @@ -1,2 +1,2 @@ -# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0004_multiple_UTF-8_characters_0a09d7ee1e23c509e5e6846c86823081.txt b/test/snapshots/lexer/utf8_test/test_0004_multiple_UTF-8_characters_0a09d7ee1e23c509e5e6846c86823081.txt index 94bb9023e..5421215be 100644 --- a/test/snapshots/lexer/utf8_test/test_0004_multiple_UTF-8_characters_0a09d7ee1e23c509e5e6846c86823081.txt +++ b/test/snapshots/lexer/utf8_test/test_0004_multiple_UTF-8_characters_0a09d7ee1e23c509e5e6846c86823081.txt @@ -1,4 +1,4 @@ -# -# -# +# +# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0005_mixed_ASCII_and_UTF-8_60791161b6a23965fd2c7c4f28b40ef7.txt b/test/snapshots/lexer/utf8_test/test_0005_mixed_ASCII_and_UTF-8_60791161b6a23965fd2c7c4f28b40ef7.txt index 77b790b5f..4d6753811 100644 --- a/test/snapshots/lexer/utf8_test/test_0005_mixed_ASCII_and_UTF-8_60791161b6a23965fd2c7c4f28b40ef7.txt +++ b/test/snapshots/lexer/utf8_test/test_0005_mixed_ASCII_and_UTF-8_60791161b6a23965fd2c7c4f28b40ef7.txt @@ -1,6 +1,6 @@ # # -# +# # # # diff --git a/test/snapshots/lexer/utf8_test/test_0006_UTF-8_in_HTML_tag_23d7cee67799f39f80ff3c8c3f123876.txt b/test/snapshots/lexer/utf8_test/test_0006_UTF-8_in_HTML_tag_23d7cee67799f39f80ff3c8c3f123876.txt index dd5475cb9..f6d7fc568 100644 --- a/test/snapshots/lexer/utf8_test/test_0006_UTF-8_in_HTML_tag_23d7cee67799f39f80ff3c8c3f123876.txt +++ b/test/snapshots/lexer/utf8_test/test_0006_UTF-8_in_HTML_tag_23d7cee67799f39f80ff3c8c3f123876.txt @@ -1,7 +1,7 @@ # # # -# +# # # # diff --git a/test/snapshots/lexer/utf8_test/test_0007_UTF-8_in_attribute_value_33c8000ce11b738c064a2480a67cd966.txt b/test/snapshots/lexer/utf8_test/test_0007_UTF-8_in_attribute_value_33c8000ce11b738c064a2480a67cd966.txt index 589c19032..6fb37fd7b 100644 --- a/test/snapshots/lexer/utf8_test/test_0007_UTF-8_in_attribute_value_33c8000ce11b738c064a2480a67cd966.txt +++ b/test/snapshots/lexer/utf8_test/test_0007_UTF-8_in_attribute_value_33c8000ce11b738c064a2480a67cd966.txt @@ -5,9 +5,9 @@ # # # -# +# # -# +# # # # diff --git a/test/snapshots/lexer/utf8_test/test_0009_various_Unicode_symbols_56dca1fb5e06fa932b775ab821350f5d.txt b/test/snapshots/lexer/utf8_test/test_0009_various_Unicode_symbols_56dca1fb5e06fa932b775ab821350f5d.txt index f448b7330..8907d1b37 100644 --- a/test/snapshots/lexer/utf8_test/test_0009_various_Unicode_symbols_56dca1fb5e06fa932b775ab821350f5d.txt +++ b/test/snapshots/lexer/utf8_test/test_0009_various_Unicode_symbols_56dca1fb5e06fa932b775ab821350f5d.txt @@ -1,6 +1,6 @@ -# -# -# -# -# +# +# +# +# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0010_emoji_sequence_20411a338175125c89c7b53b1a7171eb.txt b/test/snapshots/lexer/utf8_test/test_0010_emoji_sequence_20411a338175125c89c7b53b1a7171eb.txt index a810aa9c8..b8c1e4ec0 100644 --- a/test/snapshots/lexer/utf8_test/test_0010_emoji_sequence_20411a338175125c89c7b53b1a7171eb.txt +++ b/test/snapshots/lexer/utf8_test/test_0010_emoji_sequence_20411a338175125c89c7b53b1a7171eb.txt @@ -1,5 +1,5 @@ -# -# -# -# +# +# +# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0011_Chinese_characters_65396ee4aad0b4f17aacd1c6112ee364.txt b/test/snapshots/lexer/utf8_test/test_0011_Chinese_characters_65396ee4aad0b4f17aacd1c6112ee364.txt index eb78bbc16..aa30fe6c3 100644 --- a/test/snapshots/lexer/utf8_test/test_0011_Chinese_characters_65396ee4aad0b4f17aacd1c6112ee364.txt +++ b/test/snapshots/lexer/utf8_test/test_0011_Chinese_characters_65396ee4aad0b4f17aacd1c6112ee364.txt @@ -1,5 +1,5 @@ -# -# -# -# +# +# +# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0012_Arabic_text_9530db02d3c8217be00c1aa98ec51861.txt b/test/snapshots/lexer/utf8_test/test_0012_Arabic_text_9530db02d3c8217be00c1aa98ec51861.txt index f53291e81..0c2ee1d7f 100644 --- a/test/snapshots/lexer/utf8_test/test_0012_Arabic_text_9530db02d3c8217be00c1aa98ec51861.txt +++ b/test/snapshots/lexer/utf8_test/test_0012_Arabic_text_9530db02d3c8217be00c1aa98ec51861.txt @@ -1,6 +1,6 @@ -# -# -# -# -# +# +# +# +# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0013_mixed_UTF-8_with_HTML_structure_2eedd7e4e1585b52553db2fcf70bdfb9.txt b/test/snapshots/lexer/utf8_test/test_0013_mixed_UTF-8_with_HTML_structure_2eedd7e4e1585b52553db2fcf70bdfb9.txt index 82f99cc80..02fb786f1 100644 --- a/test/snapshots/lexer/utf8_test/test_0013_mixed_UTF-8_with_HTML_structure_2eedd7e4e1585b52553db2fcf70bdfb9.txt +++ b/test/snapshots/lexer/utf8_test/test_0013_mixed_UTF-8_with_HTML_structure_2eedd7e4e1585b52553db2fcf70bdfb9.txt @@ -5,19 +5,19 @@ # # # -# +# # # # -# +# # # # # # -# +# # -# +# # # # diff --git a/test/snapshots/lexer/utf8_test/test_0014_UTF-8_line_breaks_and_positioning_87772e0d3b85d8cab09a1c354d70b213.txt b/test/snapshots/lexer/utf8_test/test_0014_UTF-8_line_breaks_and_positioning_87772e0d3b85d8cab09a1c354d70b213.txt index 199794c3f..9d6921e1b 100644 --- a/test/snapshots/lexer/utf8_test/test_0014_UTF-8_line_breaks_and_positioning_87772e0d3b85d8cab09a1c354d70b213.txt +++ b/test/snapshots/lexer/utf8_test/test_0014_UTF-8_line_breaks_and_positioning_87772e0d3b85d8cab09a1c354d70b213.txt @@ -1,6 +1,6 @@ -# +# # -# +# # -# +# # diff --git a/test/snapshots/lexer/utf8_test/test_0015_complex_UTF-8_with_ERB_b6276e3bed3faa902628e7bd34d5d3d7.txt b/test/snapshots/lexer/utf8_test/test_0015_complex_UTF-8_with_ERB_b6276e3bed3faa902628e7bd34d5d3d7.txt index 3169a8880..105da8fef 100644 --- a/test/snapshots/lexer/utf8_test/test_0015_complex_UTF-8_with_ERB_b6276e3bed3faa902628e7bd34d5d3d7.txt +++ b/test/snapshots/lexer/utf8_test/test_0015_complex_UTF-8_with_ERB_b6276e3bed3faa902628e7bd34d5d3d7.txt @@ -1,4 +1,4 @@ # -# +# # # From bfd36c7e6804f385217de98a77cd77c734a2490b Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Wed, 17 Sep 2025 01:23:51 +0100 Subject: [PATCH 11/34] Dev Tools: Also add `zed` as available editor --- javascript/packages/dev-tools/src/herb-overlay.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/packages/dev-tools/src/herb-overlay.ts b/javascript/packages/dev-tools/src/herb-overlay.ts index 70aa8b5a4..49cc8aff3 100644 --- a/javascript/packages/dev-tools/src/herb-overlay.ts +++ b/javascript/packages/dev-tools/src/herb-overlay.ts @@ -930,6 +930,7 @@ export class HerbOverlay { const editors = [ `cursor://file/${absolutePath}:${line}:${column}`, `vscode://file/${absolutePath}:${line}:${column}`, + `zed://file/${absolutePath}:${line}:${column}`, `subl://open?url=file://${absolutePath}&line=${line}&column=${column}`, `atom://core/open/file?filename=${absolutePath}&line=${line}&column=${column}`, `txmt://open?url=file://${absolutePath}&line=${line}&column=${column}`, From 6699f71c4c1e89bb9d30b83580b9b7594e3118bb Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Wed, 17 Sep 2025 03:05:54 +0200 Subject: [PATCH 12/34] Parser: Fix `
bar
` skipping over the closing bracket from the opening div (#501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `parser_advance` consumes the `TOKEN_HTML_TAG_END`, which ends up not closing the opening tag. Snapshot diff (most notably, only a single `HTMLAttributeNode` and `HTMLCloseTagNode` now appears):
Diff

```patch diff --git a/test/snapshots/parser/attributes_test/test_0046_Empty_attribute_value_with_closing_bracket_immediatly_following_it_56df6b7e184a50db1eac62508206a332.txt b/test/snapshots/parser/attributes_test/test_0046_Empty_attribute_value_with_closing_bracket_immediatly_following_it_56df6b7e184a50db1eac62508206a332.txt index 41997bb..0f1e93e 100644 --- a/test/snapshots/parser/attributes_test/test_0046_Empty_attribute_value_with_closing_bracket_immediatly_following_it_56df6b7e184a50db1eac62508206a332.txt +++ b/test/snapshots/parser/attributes_test/test_0046_Empty_attribute_value_with_closing_bracket_immediatly_following_it_56df6b7e184a50db1eac62508206a332.txt @@ -1,61 +1,49 @@ @ DocumentNode (location: (1:0)-(1:38)) -├── errors: (1 error) -│ └── @ UnclosedElementError (location: (1:38)-(1:38)) -│ ├── message: "Tag `

` opened at (1:1) was never closed before the end of document." -│ └── opening_tag: "div" (location: (1:1)-(1:4)) -│ └── children: (1 item) └── @ HTMLElementNode (location: (1:0)-(1:38)) - ├── errors: (1 error) - │ └── @ MissingClosingTagError (location: (1:1)-(1:4)) - │ ├── message: "Opening tag `
` at (1:1) doesn't have a matching closing tag `
`." - │ └── opening_tag: "div" (location: (1:1)-(1:4)) - │ ├── open_tag: - │ └── @ HTMLOpenTagNode (location: (1:0)-(1:38)) + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:21)) │ ├── tag_opening: "<" (location: (1:0)-(1:1)) │ ├── tag_name: "div" (location: (1:1)-(1:4)) - │ ├── tag_closing: ">" (location: (1:37)-(1:38)) - │ ├── children: (2 items) - │ │ ├── @ HTMLAttributeNode (location: (1:5)-(1:21)) - │ │ │ ├── name: - │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:19)) - │ │ │ │ └── children: (1 item) - │ │ │ │ └── @ LiteralNode (location: (1:5)-(1:19)) - │ │ │ │ └── content: "attribute-name" - │ │ │ │ - │ │ │ │ - │ │ │ ├── equals: "=" (location: (1:19)-(1:20)) - │ │ │ └── value: - │ │ │ └── @ HTMLAttributeValueNode (location: (1:20)-(1:21)) - │ │ │ ├── errors: (1 error) - │ │ │ │ └── @ UnexpectedError (location: (1:20)-(1:21)) - │ │ │ │ ├── message: "Unexpected Token. Expected: `TOKEN_IDENTIFIER, TOKEN_QUOTE, TOKEN_ERB_START`, found: `TOKEN_HTML_TAG_END`." - │ │ │ │ ├── description: "Unexpected Token" - │ │ │ │ ├── expected: "TOKEN_IDENTIFIER, TOKEN_QUOTE, TOKEN_ERB_START" - │ │ │ │ └── found: "TOKEN_HTML_TAG_END" - │ │ │ │ - │ │ │ ├── open_quote: ∅ - │ │ │ ├── children: [] - │ │ │ ├── close_quote: ∅ - │ │ │ └── quoted: false - │ │ │ - │ │ │ - │ │ └── @ HTMLAttributeNode (location: (1:21)-(1:37)) + │ ├── tag_closing: ">" (location: (1:20)-(1:21)) + │ ├── children: (1 item) + │ │ └── @ HTMLAttributeNode (location: (1:5)-(1:21)) │ │ ├── name: - │ │ │ └── @ HTMLAttributeNameNode (location: (1:21)-(1:37)) + │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:19)) │ │ │ └── children: (1 item) - │ │ │ └── @ LiteralNode (location: (1:21)-(1:37)) - │ │ │ └── content: "div-content" (location: (1:37)-(1:38)) + │ ├── is_void: false └── source: "HTML" \ No newline at end of file ```

--- src/parser.c | 14 ++---- test/parser/attributes_test.rb | 4 ++ ...ng_it_56df6b7e184a50db1eac62508206a332.txt | 49 +++++++++++++++++++ 3 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 test/snapshots/parser/attributes_test/test_0046_Empty_attribute_value_with_closing_bracket_immediatly_following_it_56df6b7e184a50db1eac62508206a332.txt diff --git a/src/parser.c b/src/parser.c index c7dd7c310..fbecd14a3 100644 --- a/src/parser.c +++ b/src/parser.c @@ -555,14 +555,12 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser return value; } - token_T* token = parser_advance(parser); - append_unexpected_error( "Unexpected Token", "TOKEN_IDENTIFIER, TOKEN_QUOTE, TOKEN_ERB_START", - token_type_to_string(token->type), - token->location->start, - token->location->end, + token_type_to_string(parser->current_token->type), + parser->current_token->location->start, + parser->current_token->location->end, errors ); @@ -571,13 +569,11 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser children, NULL, false, - token->location->start, - token->location->end, + parser->current_token->location->start, + parser->current_token->location->end, errors ); - token_free(token); - return value; } diff --git a/test/parser/attributes_test.rb b/test/parser/attributes_test.rb index e6cebb610..789d032a2 100644 --- a/test/parser/attributes_test.rb +++ b/test/parser/attributes_test.rb @@ -191,5 +191,9 @@ class AttributesTest < Minitest::Spec test "Vue directive with namespace-like syntax" do assert_parsed_snapshot(%(
)) end + + test "Empty attribute value with closing bracket immediatly following it" do + assert_parsed_snapshot(%(
div-content
)) + end end end diff --git a/test/snapshots/parser/attributes_test/test_0046_Empty_attribute_value_with_closing_bracket_immediatly_following_it_56df6b7e184a50db1eac62508206a332.txt b/test/snapshots/parser/attributes_test/test_0046_Empty_attribute_value_with_closing_bracket_immediatly_following_it_56df6b7e184a50db1eac62508206a332.txt new file mode 100644 index 000000000..0f1e93e7c --- /dev/null +++ b/test/snapshots/parser/attributes_test/test_0046_Empty_attribute_value_with_closing_bracket_immediatly_following_it_56df6b7e184a50db1eac62508206a332.txt @@ -0,0 +1,49 @@ +@ DocumentNode (location: (1:0)-(1:38)) +└── children: (1 item) + └── @ HTMLElementNode (location: (1:0)-(1:38)) + ├── open_tag: + │ └── @ HTMLOpenTagNode (location: (1:0)-(1:21)) + │ ├── tag_opening: "<" (location: (1:0)-(1:1)) + │ ├── tag_name: "div" (location: (1:1)-(1:4)) + │ ├── tag_closing: ">" (location: (1:20)-(1:21)) + │ ├── children: (1 item) + │ │ └── @ HTMLAttributeNode (location: (1:5)-(1:21)) + │ │ ├── name: + │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:19)) + │ │ │ └── children: (1 item) + │ │ │ └── @ LiteralNode (location: (1:5)-(1:19)) + │ │ │ └── content: "attribute-name" + │ │ │ + │ │ │ + │ │ ├── equals: "=" (location: (1:19)-(1:20)) + │ │ └── value: + │ │ └── @ HTMLAttributeValueNode (location: (1:20)-(1:21)) + │ │ ├── errors: (1 error) + │ │ │ └── @ UnexpectedError (location: (1:20)-(1:21)) + │ │ │ ├── message: "Unexpected Token. Expected: `TOKEN_IDENTIFIER, TOKEN_QUOTE, TOKEN_ERB_START`, found: `TOKEN_HTML_TAG_END`." + │ │ │ ├── description: "Unexpected Token" + │ │ │ ├── expected: "TOKEN_IDENTIFIER, TOKEN_QUOTE, TOKEN_ERB_START" + │ │ │ └── found: "TOKEN_HTML_TAG_END" + │ │ │ + │ │ ├── open_quote: ∅ + │ │ ├── children: [] + │ │ ├── close_quote: ∅ + │ │ └── quoted: false + │ │ + │ │ + │ └── is_void: false + │ + ├── tag_name: "div" (location: (1:1)-(1:4)) + ├── body: (1 item) + │ └── @ HTMLTextNode (location: (1:21)-(1:32)) + │ └── content: "div-content" + │ + ├── close_tag: + │ └── @ HTMLCloseTagNode (location: (1:32)-(1:38)) + │ ├── tag_opening: "" (location: (1:37)-(1:38)) + │ + ├── is_void: false + └── source: "HTML" \ No newline at end of file From bfeda3f331e629ada53c6edd71824511e8c958a8 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Wed, 17 Sep 2025 04:43:46 +0300 Subject: [PATCH 13/34] Engine: Add `visitors` for modifying AST before compiling (#502) This pull request adds a `visitors` option to the `Herb::Engine` for preprocessing the AST before the template gets compiled. This allows us to refactor/soft-deprecate the `debug` option, since we can just pass the `Herb::Engine::DebugVisitor` as a visitor for preprocessing the AST before compiling the template. It also allows to implement custom visitors that could implement new syntax/transformations/rewrites etc. (i.e use `` syntax, erase all HTML Comments, strip certain attributes, ...) --- lib/herb/engine.rb | 23 +++++-- lib/herb/engine/debug_visitor.rb | 62 +++++++++++------ sig/herb/engine.rbs | 5 ++ sig/herb/engine/debug_visitor.rbs | 6 +- test/engine_visitors_test.rb | 68 +++++++++++++++++++ ...tests_8bcb5712e0fc1e7b6a6b8639a98f4e14.txt | 2 +- 6 files changed, 137 insertions(+), 29 deletions(-) create mode 100644 test/engine_visitors_test.rb diff --git a/lib/herb/engine.rb b/lib/herb/engine.rb index e48988d61..fe4d1c983 100644 --- a/lib/herb/engine.rb +++ b/lib/herb/engine.rb @@ -17,7 +17,7 @@ module Herb class Engine attr_reader :src, :filename, :project_path, :relative_file_path, :bufvar, :debug, :content_for_head, - :validation_error_template + :validation_error_template, :visitors ESCAPE_TABLE = { "&" => "&", @@ -51,6 +51,16 @@ def initialize(input, properties = {}) @content_for_head = properties[:content_for_head] @validation_error_template = nil @validation_mode = properties.fetch(:validation_mode, :raise) + @visitors = properties.fetch(:visitors, default_visitors) + + if @debug && @visitors.empty? + debug_visitor = DebugVisitor.new( + file_path: @filename, + project_path: @project_path + ) + + @visitors << debug_visitor + end unless [:raise, :overlay, :none].include?(@validation_mode) raise ArgumentError, @@ -109,12 +119,12 @@ def initialize(input, properties = {}) add_validation_overlay(validation_errors, input) if @validation_mode == :overlay && validation_errors&.any? - if @debug - debug_visitor = DebugVisitor.new(self) - ast.accept(debug_visitor) + @visitors.each do |visitor| + ast.accept(visitor) end compiler = Compiler.new(self, properties) + ast.accept(compiler) compiler.generate_output @@ -361,5 +371,10 @@ def add_parser_error_overlay(parser_errors, input) error_html = overlay_generator.generate_html @validation_error_template = "" end + + #: () -> Array[Herb::Visitor] + def default_visitors + [] + end end end diff --git a/lib/herb/engine/debug_visitor.rb b/lib/herb/engine/debug_visitor.rb index 2a1dc1fe7..fdef692ad 100644 --- a/lib/herb/engine/debug_visitor.rb +++ b/lib/herb/engine/debug_visitor.rb @@ -3,10 +3,26 @@ module Herb class Engine class DebugVisitor < Herb::Visitor - def initialize(engine) + def initialize(file_path: nil, project_path: nil) super() - @engine = engine + @filename = case file_path + when ::Pathname + file_path + when String + file_path.empty? ? nil : ::Pathname.new(file_path) + end + + @project_path = case project_path + when ::Pathname + project_path + when String + ::Pathname.new(project_path) + else + ::Pathname.new(Dir.pwd) + end + + @relative_file_path = calculate_relative_path @top_level_elements = [] #: Array[Herb::AST::HTMLElementNode] @element_stack = [] #: Array[String] @debug_attributes_applied = false @@ -16,13 +32,7 @@ def initialize(engine) @erb_nodes_to_wrap = [] #: Array[Herb::AST::ERBContentNode] end - def debug_enabled? - @engine.debug - end - def visit_document_node(node) - return unless debug_enabled? - find_top_level_elements(node) super @@ -31,8 +41,6 @@ def visit_document_node(node) end def visit_html_element_node(node) - return super unless debug_enabled? - tag_name = node.tag_name&.value&.downcase @element_stack.push(tag_name) if tag_name @@ -62,7 +70,7 @@ def visit_html_doctype_node(node) end def visit_erb_content_node(node) - if debug_enabled? && !@in_attribute && !@in_html_comment && !@in_html_doctype && !in_excluded_context? && erb_output?(node.tag_opening.value) + if !@in_attribute && !@in_html_comment && !@in_html_doctype && !in_excluded_context? && erb_output?(node.tag_opening.value) code = node.content.value.strip @erb_nodes_to_wrap << node unless complex_rails_helper?(code) @@ -77,6 +85,18 @@ def visit_erb_yield_node(_node) private + def calculate_relative_path + return "unknown" unless @filename + + if @filename.absolute? + @filename.relative_path_from(@project_path).to_s + else + @filename.to_s + end + rescue ArgumentError + @filename.to_s + end + def wrap_all_erb_nodes(node) replace_erb_nodes_recursive(node) end @@ -151,9 +171,9 @@ def add_debug_attributes_to_element(open_tag_node) debug_attributes = [ create_debug_attribute("data-herb-debug-outline-type", view_type), - create_debug_attribute("data-herb-debug-file-name", @engine.filename&.basename&.to_s || "unknown"), - create_debug_attribute("data-herb-debug-file-relative-path", @engine.relative_file_path || ""), - create_debug_attribute("data-herb-debug-file-full-path", @engine.filename&.to_s || "unknown") + create_debug_attribute("data-herb-debug-file-name", @filename&.basename&.to_s || "unknown"), + create_debug_attribute("data-herb-debug-file-relative-path", @relative_file_path || "unknown"), + create_debug_attribute("data-herb-debug-file-full-path", @filename&.to_s || "unknown") ] if @top_level_elements.length > 1 @@ -206,9 +226,9 @@ def create_debug_span_for_erb(erb_node) debug_attributes = [ create_debug_attribute("data-herb-debug-outline-type", outline_type), create_debug_attribute("data-herb-debug-erb", escaped_erb), - create_debug_attribute("data-herb-debug-file-name", @engine.filename&.basename.to_s), - create_debug_attribute("data-herb-debug-file-relative-path", @engine.relative_file_path || ""), - create_debug_attribute("data-herb-debug-file-full-path", @engine.filename.to_s), + create_debug_attribute("data-herb-debug-file-name", @filename&.basename&.to_s || "unknown"), + create_debug_attribute("data-herb-debug-file-relative-path", @relative_file_path || "unknown"), + create_debug_attribute("data-herb-debug-file-full-path", @filename&.to_s || "unknown"), create_debug_attribute("data-herb-debug-inserted", "true") ] @@ -256,16 +276,16 @@ def determine_view_type end def partial? - return false unless @engine.filename + return false unless @filename - basename = @engine.filename.basename.to_s + basename = @filename.basename.to_s basename.start_with?("_") end def component? - return false unless @engine.filename + return false unless @filename - path = @engine.filename.to_s + path = @filename.to_s path.include?("/components/") end diff --git a/sig/herb/engine.rbs b/sig/herb/engine.rbs index 537693bbd..c8e9a79ce 100644 --- a/sig/herb/engine.rbs +++ b/sig/herb/engine.rbs @@ -18,6 +18,8 @@ module Herb attr_reader validation_error_template: untyped + attr_reader visitors: untyped + ESCAPE_TABLE: untyped class CompilationError < StandardError @@ -68,5 +70,8 @@ module Herb def escape_attr: (untyped text) -> untyped def add_parser_error_overlay: (untyped parser_errors, untyped input) -> untyped + + # : () -> Array[Herb::Visitor] + def default_visitors: () -> Array[Herb::Visitor] end end diff --git a/sig/herb/engine/debug_visitor.rbs b/sig/herb/engine/debug_visitor.rbs index afb8fda7f..b5a10d59f 100644 --- a/sig/herb/engine/debug_visitor.rbs +++ b/sig/herb/engine/debug_visitor.rbs @@ -3,9 +3,7 @@ module Herb class Engine class DebugVisitor < Herb::Visitor - def initialize: (untyped engine) -> untyped - - def debug_enabled?: () -> untyped + def initialize: (?file_path: untyped, ?project_path: untyped) -> untyped def visit_document_node: (untyped node) -> untyped @@ -23,6 +21,8 @@ module Herb private + def calculate_relative_path: () -> untyped + def wrap_all_erb_nodes: (untyped node) -> untyped # Creates a dummy location for AST nodes that don't need real location info diff --git a/test/engine_visitors_test.rb b/test/engine_visitors_test.rb new file mode 100644 index 000000000..9292dfbc8 --- /dev/null +++ b/test/engine_visitors_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require_relative "test_helper" + +class EngineVisitorsTest < Minitest::Spec + test "engine works without any visitors" do + html = "
Hello World
" + + engine = Herb::Engine.new(html) + + expected = "_buf = ::String.new;\n _buf << '
Hello World
'.freeze;\n_buf.to_s\n" + assert_equal expected, engine.src + end + + test "engine runs visitors in the order provided" do + html = "
Test
" + + execution_order = [] + + visitor1 = Class.new(Herb::Visitor) do + define_method(:initialize) do |order_array| + super() + @order_array = order_array + end + + define_method(:visit_document_node) do |node| + @order_array << "visitor1" + super(node) + end + end.new(execution_order) + + visitor2 = Class.new(Herb::Visitor) do + define_method(:initialize) do |order_array| + super() + @order_array = order_array + end + + define_method(:visit_document_node) do |node| + @order_array << "visitor2" + super(node) + end + end.new(execution_order) + + visitors = [visitor1, visitor2] + + engine = Herb::Engine.new(html, visitors: visitors) + + assert_equal ["visitor1", "visitor2"], execution_order + + expected = "_buf = ::String.new;\n _buf << '
Test
'.freeze;\n_buf.to_s\n" + assert_equal expected, engine.src + end + + test "debug visitor can still be used explicitly" do + html = "
Debug test
" + + debug_visitor = Herb::Engine::DebugVisitor.new( + file_path: "test.html.erb", + project_path: "/project" + ) + + visitors = [debug_visitor] + + engine = Herb::Engine.new(html, visitors: visitors, debug: false) + + refute_nil engine.src + end +end diff --git a/test/snapshots/engine/debug_mode_test/test_0047_regular_div_content_still_gets_debug_spans_after_excluded_context_tests_8bcb5712e0fc1e7b6a6b8639a98f4e14.txt b/test/snapshots/engine/debug_mode_test/test_0047_regular_div_content_still_gets_debug_spans_after_excluded_context_tests_8bcb5712e0fc1e7b6a6b8639a98f4e14.txt index 13ff8c120..7041fb7c3 100644 --- a/test/snapshots/engine/debug_mode_test/test_0047_regular_div_content_still_gets_debug_spans_after_excluded_context_tests_8bcb5712e0fc1e7b6a6b8639a98f4e14.txt +++ b/test/snapshots/engine/debug_mode_test/test_0047_regular_div_content_still_gets_debug_spans_after_excluded_context_tests_8bcb5712e0fc1e7b6a6b8639a98f4e14.txt @@ -1,3 +1,3 @@ _buf = ::String.new; - _buf << '
'.freeze; _buf << (@content).to_s; _buf << '
'.freeze; + _buf << '
'.freeze; _buf << (@content).to_s; _buf << '
'.freeze; _buf.to_s From 44ca9b79b0c5e099bd7c18d647fd78927ac08fd5 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Wed, 17 Sep 2025 02:57:43 +0100 Subject: [PATCH 14/34] `v0.7.2` --- Gemfile.lock | 2 +- docs/package.json | 6 ++--- javascript/packages/browser/package.json | 4 ++-- .../packages/browser/test/browser.test.ts | 2 +- javascript/packages/core/package.json | 2 +- javascript/packages/dev-tools/package.json | 4 ++-- javascript/packages/formatter/package.json | 6 ++--- .../herb-language-server/package.json | 4 ++-- javascript/packages/highlighter/package.json | 6 ++--- .../packages/language-server/package.json | 8 +++---- javascript/packages/linter/README.md | 4 ++-- javascript/packages/linter/package.json | 10 ++++---- .../test/__snapshots__/cli.test.ts.snap | 24 +++++++++---------- javascript/packages/node-wasm/package.json | 4 ++-- .../packages/node-wasm/test/node-wasm.test.ts | 2 +- javascript/packages/node/package.json | 4 ++-- javascript/packages/node/test/node.test.ts | 2 +- javascript/packages/printer/package.json | 4 ++-- .../packages/stimulus-lint/package.json | 10 ++++---- .../tailwind-class-sorter/package.json | 2 +- javascript/packages/vscode/package.json | 8 +++---- lib/herb/version.rb | 2 +- playground/package.json | 6 ++--- src/include/version.h | 2 +- test/c/test_herb.c | 2 +- test/herb_test.rb | 2 +- 26 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3d418004a..86b35fc06 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,7 +17,7 @@ GIT PATH remote: . specs: - herb (0.7.1) + herb (0.7.2) GEM remote: https://rubygems.org/ diff --git a/docs/package.json b/docs/package.json index 026c8fd36..ede020696 100644 --- a/docs/package.json +++ b/docs/package.json @@ -19,9 +19,9 @@ "fetch:contributors": "mkdir -p .vitepress/data/ && gh api -X get https://api.github.com/repos/marcoroth/herb/contributors > .vitepress/data/contributors.json" }, "dependencies": { - "@herb-tools/browser": "0.7.1", - "@herb-tools/core": "0.7.1", - "@herb-tools/node": "0.7.1" + "@herb-tools/browser": "0.7.2", + "@herb-tools/core": "0.7.2", + "@herb-tools/node": "0.7.2" }, "devDependencies": { "@shikijs/vitepress-twoslash": "^3.4.2", diff --git a/javascript/packages/browser/package.json b/javascript/packages/browser/package.json index fbfed9744..a4304a1ef 100644 --- a/javascript/packages/browser/package.json +++ b/javascript/packages/browser/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/browser", - "version": "0.7.1", + "version": "0.7.2", "description": "WebAssembly-based HTML-aware ERB parser for browsers.", "type": "module", "license": "MIT", @@ -34,7 +34,7 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.1" + "@herb-tools/core": "0.7.2" }, "files": [ "package.json", diff --git a/javascript/packages/browser/test/browser.test.ts b/javascript/packages/browser/test/browser.test.ts index 17338ff46..76562c374 100644 --- a/javascript/packages/browser/test/browser.test.ts +++ b/javascript/packages/browser/test/browser.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/browser", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/browser@0.7.1, @herb-tools/core@0.7.1, libprism@1.5.1, libherb@0.7.1 (WebAssembly)") + expect(version).toBe("@herb-tools/browser@0.7.2, @herb-tools/core@0.7.2, libprism@1.5.1, libherb@0.7.2 (WebAssembly)") }) test("parse() can process a simple template", async () => { diff --git a/javascript/packages/core/package.json b/javascript/packages/core/package.json index 584b138c6..574201479 100644 --- a/javascript/packages/core/package.json +++ b/javascript/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/core", - "version": "0.7.1", + "version": "0.7.2", "description": "Core module exporting shared interfaces, AST node definitions, and common utilities for Herb", "type": "module", "license": "MIT", diff --git a/javascript/packages/dev-tools/package.json b/javascript/packages/dev-tools/package.json index 777a3e6ef..78f002cdb 100644 --- a/javascript/packages/dev-tools/package.json +++ b/javascript/packages/dev-tools/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/dev-tools", - "version": "0.7.1", + "version": "0.7.2", "description": "Development tools for visual debugging in HTML+ERB templates", "type": "module", "license": "MIT", @@ -30,7 +30,7 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.1" + "@herb-tools/core": "0.7.2" }, "files": [ "package.json", diff --git a/javascript/packages/formatter/package.json b/javascript/packages/formatter/package.json index 0410310f7..7d9ce08ae 100644 --- a/javascript/packages/formatter/package.json +++ b/javascript/packages/formatter/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/formatter", - "version": "0.7.1", + "version": "0.7.2", "description": "Auto-formatter for HTML+ERB templates with intelligent indentation, line wrapping, and ERB-aware pretty-printing.", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -35,8 +35,8 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.1", - "@herb-tools/printer": "0.7.1" + "@herb-tools/core": "0.7.2", + "@herb-tools/printer": "0.7.2" }, "devDependencies": { "glob": "^11.0.3" diff --git a/javascript/packages/herb-language-server/package.json b/javascript/packages/herb-language-server/package.json index e823118e6..15521e51a 100644 --- a/javascript/packages/herb-language-server/package.json +++ b/javascript/packages/herb-language-server/package.json @@ -1,7 +1,7 @@ { "name": "herb-language-server", "description": "Placeholder package to reserve the herb-language-server name on NPM; use @herb-tools/language-server instead.", - "version": "0.7.1", + "version": "0.7.2", "author": "Marco Roth", "license": "MIT", "engines": { @@ -45,6 +45,6 @@ "dist/" ], "dependencies": { - "@herb-tools/language-server": "0.7.1" + "@herb-tools/language-server": "0.7.2" } } diff --git a/javascript/packages/highlighter/package.json b/javascript/packages/highlighter/package.json index af8ee4620..8522b7953 100644 --- a/javascript/packages/highlighter/package.json +++ b/javascript/packages/highlighter/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/highlighter", - "version": "0.7.1", + "version": "0.7.2", "description": "Syntax highlighter and diagnostic renderer for HTML+ERB templates.", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -35,8 +35,8 @@ "prepublishOnly": "yarn clean && yarn build && yarn test" }, "dependencies": { - "@herb-tools/core": "0.7.1", - "@herb-tools/node-wasm": "0.7.1", + "@herb-tools/core": "0.7.2", + "@herb-tools/node-wasm": "0.7.2", "glob": "^11.0.3" }, "files": [ diff --git a/javascript/packages/language-server/package.json b/javascript/packages/language-server/package.json index 53da675ba..f6465c7d0 100644 --- a/javascript/packages/language-server/package.json +++ b/javascript/packages/language-server/package.json @@ -1,7 +1,7 @@ { "name": "@herb-tools/language-server", "description": "Herb HTML+ERB Language Tools and Language Server Protocol integration.", - "version": "0.7.1", + "version": "0.7.2", "author": "Marco Roth", "license": "MIT", "engines": { @@ -45,9 +45,9 @@ "dist/" ], "dependencies": { - "@herb-tools/formatter": "0.7.1", - "@herb-tools/linter": "0.7.1", - "@herb-tools/node-wasm": "0.7.1", + "@herb-tools/formatter": "0.7.2", + "@herb-tools/linter": "0.7.2", + "@herb-tools/node-wasm": "0.7.2", "dedent": "^1.6.0", "vscode-languageserver": "^9.0.1", "vscode-languageserver-textdocument": "^1.0.12" diff --git a/javascript/packages/linter/README.md b/javascript/packages/linter/README.md index e0272696a..9c7957bd9 100644 --- a/javascript/packages/linter/README.md +++ b/javascript/packages/linter/README.md @@ -184,7 +184,7 @@ npx @herb-tools/linter --format=simple --github **Example: `--github` (GitHub annotations + detailed format)** ``` -::error file=template.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required `alt` attribute on `` tag [html-img-require-alt]%0A%0A%0Atemplate.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A +::error file=template.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.2::Missing required `alt` attribute on `` tag [html-img-require-alt]%0A%0A%0Atemplate.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A [error] Missing required `alt` attribute on `` tag [html-img-require-alt] @@ -199,7 +199,7 @@ template.html.erb:3:3 **Example: `--format=simple --github` (GitHub annotations + simple format)** ``` -::error file=template.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required `alt` attribute on `` tag [html-img-require-alt]%0A%0A%0Atemplate.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A +::error file=template.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.2::Missing required `alt` attribute on `` tag [html-img-require-alt]%0A%0A%0Atemplate.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A template.html.erb: 3:3 ✗ Missing required `alt` attribute on `` tag [html-img-require-alt] diff --git a/javascript/packages/linter/package.json b/javascript/packages/linter/package.json index 4ce916335..690e628ef 100644 --- a/javascript/packages/linter/package.json +++ b/javascript/packages/linter/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/linter", - "version": "0.7.1", + "version": "0.7.2", "description": "HTML+ERB linter for validating HTML structure and enforcing best practices", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -39,10 +39,10 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.1", - "@herb-tools/highlighter": "0.7.1", - "@herb-tools/node-wasm": "0.7.1", - "@herb-tools/printer": "0.7.1", + "@herb-tools/core": "0.7.2", + "@herb-tools/highlighter": "0.7.2", + "@herb-tools/node-wasm": "0.7.2", + "@herb-tools/printer": "0.7.2", "glob": "^11.0.3" }, "files": [ diff --git a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap index 103b947d0..96fc07508 100644 --- a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap +++ b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap @@ -1,11 +1,11 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`CLI Output Formatting > GitHub Actions format escapes special characters in messages 1`] = ` -"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A +"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.2::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.2::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.2::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A [error] Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. (html-img-require-alt) @@ -55,7 +55,7 @@ test/fixtures/test-file-with-errors.html.erb:2:22 `; exports[`CLI Output Formatting > GitHub Actions format includes rule codes 1`] = ` -"::error file=test/fixtures/no-trailing-newline.html.erb,line=1,col=29,title=erb-requires-trailing-newline • @herb-tools/linter@0.7.1::File must end with trailing newline [erb-requires-trailing-newline]%0A%0A%0Atest/fixtures/no-trailing-newline.html.erb:1:29%0A%0A → 1 │
No trailing newline
%0A │ ~%0A +"::error file=test/fixtures/no-trailing-newline.html.erb,line=1,col=29,title=erb-requires-trailing-newline • @herb-tools/linter@0.7.2::File must end with trailing newline [erb-requires-trailing-newline]%0A%0A%0Atest/fixtures/no-trailing-newline.html.erb:1:29%0A%0A → 1 │
No trailing newline
%0A │ ~%0A [error] File must end with trailing newline (erb-requires-trailing-newline) @@ -389,9 +389,9 @@ test/fixtures/few-rule-offenses.html.erb:3:16 `; exports[`CLI Output Formatting > formats GitHub Actions output correctly for bad file 1`] = ` -"::error file=test/fixtures/bad-file.html.erb,line=1,col=1,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/bad-file.html.erb:1:1%0A%0A → 1 │ Bad file%0A │ ~~~~%0A 2 │%0A +"::error file=test/fixtures/bad-file.html.erb,line=1,col=1,title=html-tag-name-lowercase • @herb-tools/linter@0.7.2::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/bad-file.html.erb:1:1%0A%0A → 1 │ Bad file%0A │ ~~~~%0A 2 │%0A -::error file=test/fixtures/bad-file.html.erb,line=1,col=16,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Closing tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/bad-file.html.erb:1:16%0A%0A → 1 │ Bad file%0A │ ~~~~%0A 2 │%0A +::error file=test/fixtures/bad-file.html.erb,line=1,col=16,title=html-tag-name-lowercase • @herb-tools/linter@0.7.2::Closing tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/bad-file.html.erb:1:16%0A%0A → 1 │ Bad file%0A │ ~~~~%0A 2 │%0A [error] Opening tag name \`\` should be lowercase. Use \`\` instead. (html-tag-name-lowercase) @@ -431,11 +431,11 @@ exports[`CLI Output Formatting > formats GitHub Actions output correctly for cle `; exports[`CLI Output Formatting > formats GitHub Actions output correctly for file with errors 1`] = ` -"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A +"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.2::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.2::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.2::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A [error] Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. (html-img-require-alt) @@ -773,11 +773,11 @@ test/fixtures/bad-file.html.erb:1:16 `; exports[`CLI Output Formatting > uses GitHub Actions format by default when GITHUB_ACTIONS is true 1`] = ` -"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.1::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A +"::error file=test/fixtures/test-file-with-errors.html.erb,line=3,col=3,title=html-img-require-alt • @herb-tools/linter@0.7.2::Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. [html-img-require-alt]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:3:3%0A%0A 1 │
%0A 2 │ Test content%0A → 3 │ %0A │ ~~~%0A 4 │
%0A 5 │%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=3,title=html-tag-name-lowercase • @herb-tools/linter@0.7.2::Opening tag name \`\` should be lowercase. Use \`\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:3%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A -::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.1::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A +::error file=test/fixtures/test-file-with-errors.html.erb,line=2,col=22,title=html-tag-name-lowercase • @herb-tools/linter@0.7.2::Closing tag name \`
\` should be lowercase. Use \`
\` instead. [html-tag-name-lowercase]%0A%0A%0Atest/fixtures/test-file-with-errors.html.erb:2:22%0A%0A 1 │
%0A → 2 │ Test content%0A │ ~~~~%0A 3 │ %0A 4 │
%0A [error] Missing required \`alt\` attribute on \`\` tag. Add \`alt=""\` for decorative images or \`alt="description"\` for informative images. (html-img-require-alt) diff --git a/javascript/packages/node-wasm/package.json b/javascript/packages/node-wasm/package.json index 469dda9cb..9f0d1ee1f 100644 --- a/javascript/packages/node-wasm/package.json +++ b/javascript/packages/node-wasm/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/node-wasm", - "version": "0.7.1", + "version": "0.7.2", "description": "WebAssembly-based HTML-aware ERB parser for Node.js.", "type": "module", "license": "MIT", @@ -36,7 +36,7 @@ } }, "dependencies": { - "@herb-tools/core": "0.7.1" + "@herb-tools/core": "0.7.2" }, "files": [ "package.json", diff --git a/javascript/packages/node-wasm/test/node-wasm.test.ts b/javascript/packages/node-wasm/test/node-wasm.test.ts index 4ec932eca..d88c9f631 100644 --- a/javascript/packages/node-wasm/test/node-wasm.test.ts +++ b/javascript/packages/node-wasm/test/node-wasm.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/node-wasm", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/node-wasm@0.7.1, @herb-tools/core@0.7.1, libprism@1.5.1, libherb@0.7.1 (WebAssembly)") + expect(version).toBe("@herb-tools/node-wasm@0.7.2, @herb-tools/core@0.7.2, libprism@1.5.1, libherb@0.7.2 (WebAssembly)") }) test("parse() can process a simple template", async () => { diff --git a/javascript/packages/node/package.json b/javascript/packages/node/package.json index afc87e92d..2b79de74a 100644 --- a/javascript/packages/node/package.json +++ b/javascript/packages/node/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/node", - "version": "0.7.1", + "version": "0.7.2", "description": "Native Node.js addon for HTML-aware ERB parsing using Herb.", "type": "module", "license": "MIT", @@ -48,7 +48,7 @@ "host": "https://github.com/marcoroth/herb/releases/download/" }, "dependencies": { - "@herb-tools/core": "0.7.1", + "@herb-tools/core": "0.7.2", "@mapbox/node-pre-gyp": "^2.0.0", "node-addon-api": "^5.1.0", "node-pre-gyp-github": "^2.0.0" diff --git a/javascript/packages/node/test/node.test.ts b/javascript/packages/node/test/node.test.ts index afdf4e378..6f80e6434 100644 --- a/javascript/packages/node/test/node.test.ts +++ b/javascript/packages/node/test/node.test.ts @@ -17,7 +17,7 @@ describe("@herb-tools/node", () => { test("version() returns a string", async () => { const version = Herb.version expect(typeof version).toBe("string") - expect(version).toBe("@herb-tools/node@0.7.1, @herb-tools/core@0.7.1, libprism@1.5.1, libherb@0.7.1 (Node.js C++ native extension)") + expect(version).toBe("@herb-tools/node@0.7.2, @herb-tools/core@0.7.2, libprism@1.5.1, libherb@0.7.2 (Node.js C++ native extension)") }) test("parse() can process a simple template", async () => { diff --git a/javascript/packages/printer/package.json b/javascript/packages/printer/package.json index 6caa021b3..162d3bc13 100644 --- a/javascript/packages/printer/package.json +++ b/javascript/packages/printer/package.json @@ -1,6 +1,6 @@ { "name": "@herb-tools/printer", - "version": "0.7.1", + "version": "0.7.2", "description": "AST printer infrastructure and lossless reconstruction tool for HTML+ERB templates", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -37,7 +37,7 @@ "prepublishOnly": "yarn clean && yarn build && yarn test" }, "dependencies": { - "@herb-tools/core": "0.7.1", + "@herb-tools/core": "0.7.2", "glob": "^10.3.10" }, "files": [ diff --git a/javascript/packages/stimulus-lint/package.json b/javascript/packages/stimulus-lint/package.json index a55bde199..db5b5dd2b 100644 --- a/javascript/packages/stimulus-lint/package.json +++ b/javascript/packages/stimulus-lint/package.json @@ -1,6 +1,6 @@ { "name": "stimulus-lint", - "version": "0.1.1", + "version": "0.1.2", "description": "Linting rules for Stimulus controllers and HTML+ERB view templates.", "license": "MIT", "homepage": "https://herb-tools.dev", @@ -34,10 +34,10 @@ "prepublishOnly": "yarn clean && yarn build && yarn test" }, "dependencies": { - "@herb-tools/linter": "0.7.1", - "@herb-tools/core": "0.7.1", - "@herb-tools/node-wasm": "0.7.1", - "@herb-tools/highlighter": "0.7.1", + "@herb-tools/linter": "0.7.2", + "@herb-tools/core": "0.7.2", + "@herb-tools/node-wasm": "0.7.2", + "@herb-tools/highlighter": "0.7.2", "stimulus-parser": "^0.3.0" }, "files": [ diff --git a/javascript/packages/tailwind-class-sorter/package.json b/javascript/packages/tailwind-class-sorter/package.json index c06d13fb6..0fdd96580 100644 --- a/javascript/packages/tailwind-class-sorter/package.json +++ b/javascript/packages/tailwind-class-sorter/package.json @@ -2,7 +2,7 @@ "type": "module", "name": "@herb-tools/tailwind-class-sorter", "description": "Standalone Tailwind CSS class sorter with Prettier plugin compatibility, extracted from tailwindlabs/prettier-plugin-tailwindcss", - "version": "0.7.1", + "version": "0.7.2", "license": "MIT", "main": "./dist/tailwind-class-sorter.cjs", "module": "./dist/tailwind-class-sorter.esm.js", diff --git a/javascript/packages/vscode/package.json b/javascript/packages/vscode/package.json index 8ad57c695..3d4f31e6f 100644 --- a/javascript/packages/vscode/package.json +++ b/javascript/packages/vscode/package.json @@ -2,7 +2,7 @@ "name": "herb-lsp", "displayName": "Herb LSP - HTML+ERB Language Tools", "description": "VS Code extension for connecting with the Herb Language Server and Language Tools for HTML+ERB files", - "version": "0.7.1", + "version": "0.7.2", "private": true, "license": "MIT", "pricing": "Free", @@ -239,9 +239,9 @@ "prepublishOnly": "yarn clean && yarn build && yarn test" }, "devDependencies": { - "@herb-tools/formatter": "0.7.1", - "@herb-tools/linter": "0.7.1", - "@herb-tools/node-wasm": "0.7.1", + "@herb-tools/formatter": "0.7.2", + "@herb-tools/linter": "0.7.2", + "@herb-tools/node-wasm": "0.7.2", "@types/node": "20.x", "@types/vscode": "^1.43.0", "@typescript-eslint/eslint-plugin": "^8.40.0", diff --git a/lib/herb/version.rb b/lib/herb/version.rb index 1e15669b2..050283ea1 100644 --- a/lib/herb/version.rb +++ b/lib/herb/version.rb @@ -2,5 +2,5 @@ # typed: true module Herb - VERSION = "0.7.1" + VERSION = "0.7.2" end diff --git a/playground/package.json b/playground/package.json index 487bc54b5..8ba4da126 100644 --- a/playground/package.json +++ b/playground/package.json @@ -19,9 +19,9 @@ }, "dependencies": { "@alenaksu/json-viewer": "^2.0.1", - "@herb-tools/browser": "0.7.1", - "@herb-tools/formatter": "0.7.1", - "@herb-tools/linter": "0.7.1", + "@herb-tools/browser": "0.7.2", + "@herb-tools/formatter": "0.7.2", + "@herb-tools/linter": "0.7.2", "@hotwired/stimulus": "^3.2.2", "dedent": "^1.6.0", "express": "^5.1.0", diff --git a/src/include/version.h b/src/include/version.h index 3ed766735..abc6883da 100644 --- a/src/include/version.h +++ b/src/include/version.h @@ -1,6 +1,6 @@ #ifndef HERB_VERSION_H #define HERB_VERSION_H -#define HERB_VERSION "0.7.1" +#define HERB_VERSION "0.7.2" #endif diff --git a/test/c/test_herb.c b/test/c/test_herb.c index e5d4632a1..35699fac8 100644 --- a/test/c/test_herb.c +++ b/test/c/test_herb.c @@ -2,7 +2,7 @@ #include "../../src/include/herb.h" TEST(test_herb_version) - ck_assert_str_eq(herb_version(), "0.7.1"); + ck_assert_str_eq(herb_version(), "0.7.2"); END TCase *herb_tests(void) { diff --git a/test/herb_test.rb b/test/herb_test.rb index 38fd9397d..07cae4251 100644 --- a/test/herb_test.rb +++ b/test/herb_test.rb @@ -4,6 +4,6 @@ class HerbTest < Minitest::Spec test "version" do - assert_equal "herb gem v0.7.1, libprism v1.5.1, libherb v0.7.1 (Ruby C native extension)", Herb.version + assert_equal "herb gem v0.7.2, libprism v1.5.1, libherb v0.7.2 (Ruby C native extension)", Herb.version end end From 2be63e47d4da52a6f96fbbcbff9fbc7d8f3ec18b Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 18 Sep 2025 01:56:29 +0200 Subject: [PATCH 15/34] Parser: Analyze parse errors as `partial_script` (#503) --- src/analyze.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/analyze.c b/src/analyze.c index f5ad254ca..565dab812 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1107,7 +1107,8 @@ void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source char* extracted_ruby = herb_extract_ruby_with_semicolons(source); pm_parser_t parser; - pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), NULL); + pm_options_t options = { 0, .partial_script = true }; + pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), &options); pm_node_t* root = pm_parse(&parser); @@ -1115,16 +1116,11 @@ void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source error = (const pm_diagnostic_t*) error->node.next) { RUBY_PARSE_ERROR_T* parse_error = ruby_parse_error_from_prism_error(error, (AST_NODE_T*) document, source, &parser); - - // TODO: ideally this shouldn't be hard-coded - if (strcmp(parse_error->diagnostic_id, "invalid_yield") == 0) { - error_free((ERROR_T*) parse_error); - } else { - array_append(document->base.errors, parse_error); - } + array_append(document->base.errors, parse_error); } pm_node_destroy(&parser, root); pm_parser_free(&parser); + pm_options_free(&options); free(extracted_ruby); } From 54dd6448cf9be7218594ff2698a2e2df37484736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20P=C3=A9ch=C3=A8r?= Date: Fri, 19 Sep 2025 00:27:17 +0100 Subject: [PATCH 16/34] Update README.md (#508) Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb10a641e..b11b7bcf5 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Commands: bundle exec herb version Prints the versions of the Herb gem and the libherb library. ``` -For detailed information, like how you can use Herb progamatiacally in Ruby and JavaScript, visit the [documentation site](https://herb-tools.dev/bindings/ruby/reference). +For detailed information, like how you can use Herb programatically in Ruby and JavaScript, visit the [documentation site](https://herb-tools.dev/bindings/ruby/reference). ## Background and Talk From eeaf2bc34cbad0d931be94718946d082144e2f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20K=C3=A4chele?= <3810945+timkaechele@users.noreply.github.com> Date: Sun, 21 Sep 2025 18:15:12 +0100 Subject: [PATCH 17/34] Fix typo in pretty_print_analyzed_ruby method (#512) --- src/analyze.c | 2 +- src/include/pretty_print.h | 2 +- src/pretty_print.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyze.c b/src/analyze.c index 565dab812..8c0a7ea4a 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -54,7 +54,7 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) { if (strcmp(opening, "<%%") != 0 && strcmp(opening, "<%%=") != 0 && strcmp(opening, "<%#") != 0) { analyzed_ruby_T* analyzed = herb_analyze_ruby(erb_content_node->content->value); - if (false) { pretty_print_analyed_ruby(analyzed, erb_content_node->content->value); } + if (false) { pretty_print_analyzed_ruby(analyzed, erb_content_node->content->value); } erb_content_node->parsed = true; erb_content_node->valid = analyzed->valid; diff --git a/src/include/pretty_print.h b/src/include/pretty_print.h index 990cd7a17..610bc3f73 100644 --- a/src/include/pretty_print.h +++ b/src/include/pretty_print.h @@ -88,6 +88,6 @@ void pretty_print_array( void pretty_print_errors(AST_NODE_T* node, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer); -void pretty_print_analyed_ruby(analyzed_ruby_T* analyzed, const char* source); +void pretty_print_analyzed_ruby(analyzed_ruby_T* analyzed, const char* source); #endif diff --git a/src/pretty_print.c b/src/pretty_print.c index c7ec14046..ee79d4e34 100644 --- a/src/pretty_print.c +++ b/src/pretty_print.c @@ -254,7 +254,7 @@ void pretty_print_string_property( } } -void pretty_print_analyed_ruby(analyzed_ruby_T* analyzed, const char* source) { +void pretty_print_analyzed_ruby(analyzed_ruby_T* analyzed, const char* source) { printf( "------------------------\nanalyzed (%p)\n------------------------\n%s\n------------------------\n if: %i\n " " elsif: %i\n else: %i\n end: %i\n block: %i\n block_closing: %i\n case: %i\n when: %i\n for: " From c7af312e4773b3f71a0b7d41c71452228342d8d4 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Mon, 22 Sep 2025 15:52:28 +0100 Subject: [PATCH 18/34] Add missing `files` and vendor Prism to allow compiling gem from source (#515) Resolves #258 Resolves #510 --- .gitignore | 3 +++ Makefile | 2 ++ Rakefile | 47 ++++++++++++++++++++++++++++++++++++++++++- ext/herb/extconf.rb | 3 ++- herb.gemspec | 3 +++ templates/template.rb | 3 +++ 6 files changed, 59 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ed8b4ee6b..8261787ab 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,9 @@ vendor/* vendor/bundle/* vendor/cache/* +# Prism Vendor +vendor/prism/* + # Bundled .gem files pkg/* diff --git a/Makefile b/Makefile index a5c3898d2..8b09e67f9 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,7 @@ clean: rm -f $(exec) $(test_exec) $(lib_name) $(shared_lib_name) $(ruby_extension) rm -rf $(objects) $(test_objects) $(extension_objects) lib/herb/*.bundle tmp rm -rf $(prism_path) + rake prism:clean bundle_install: bundle install @@ -110,6 +111,7 @@ templates: bundle_install prism: bundle_install cd $(prism_path) && ruby templates/template.rb && make static && cd - + rake prism:vendor format: $(clang_format) -i $(project_and_extension_files) diff --git a/Rakefile b/Rakefile index fce3c6573..4f78fec4d 100644 --- a/Rakefile +++ b/Rakefile @@ -128,6 +128,51 @@ task :templates do end end +prism_vendor_path = "vendor/prism" + +namespace :prism do + desc "Setup and vendor Prism" + task :vendor do + Rake::Task["prism:clean"].execute + + prism_bundle_path = `bundle show prism`.chomp + + puts prism_bundle_path + + if prism_bundle_path.empty? + puts "Make sure to run `bundle install` in the herb project directory first" + exit 1 + end + + FileUtils.mkdir_p(prism_vendor_path) + + files = [ + "config.yml", + "Rakefile", + "src/", + "include/", + "templates/" + ] + + files.each do |file| + vendored_file_path = prism_vendor_path + "/#{file}" + puts "Vendoring '#{file}' Prism file to #{vendored_file_path}" + FileUtils.cp_r(prism_bundle_path + "/#{file}", prism_vendor_path) + end + end + + desc "Clean vendored Prism in vendor/prism/" + task :clean do + puts "Cleaning up vendored Prism at #{prism_vendor_path}..." + begin + FileUtils.rm_r(prism_vendor_path) + puts "Cleaned up vendored Prism." + rescue Errno::ENOENT + puts "Vendored prism at: #{prism_vendor_path} didn't exist. Skipping." + end + end +end + namespace :templates do desc "Watch template files and regenerate on changes" task :watch do @@ -199,4 +244,4 @@ task rbs_inline: :templates do end end -task default: [:templates, :make, :compile, :test] +task default: [:templates, "prism:vendor", :make, :compile, :test] diff --git a/ext/herb/extconf.rb b/ext/herb/extconf.rb index 9abcbfc27..5dc44cfe4 100644 --- a/ext/herb/extconf.rb +++ b/ext/herb/extconf.rb @@ -9,7 +9,8 @@ extension_name = "herb" include_path = File.expand_path("../../src/include", __dir__) -prism_path = `bundle show prism`.chomp +prism_path = File.expand_path("../../vendor/prism", __dir__) + prism_src_path = "#{prism_path}/src" prism_include_path = "#{prism_path}/include" diff --git a/herb.gemspec b/herb.gemspec index a3445ac6e..537b27864 100644 --- a/herb.gemspec +++ b/herb.gemspec @@ -26,10 +26,13 @@ Gem::Specification.new do |spec| "Makefile", "Rakefile", "README.md", + "config.yml", "lib/**/*.rb", "sig/**/*.rbs", "src/**/*.{c,h}", "ext/**/*.{c,h}", + "templates/**/*.{rb,erb}", + "vendor/prism/**/*", "exe/*" ] diff --git a/templates/template.rb b/templates/template.rb index fde2f48a6..4d5973703 100755 --- a/templates/template.rb +++ b/templates/template.rb @@ -386,6 +386,9 @@ def self.read_template(path) def self.gitignore_lines @gitignore_lines ||= File.readlines(".gitignore").map(&:chomp) + rescue Errno::ENOENT + puts "[Herb Templates] Couldn't find .gitignore" + [] end def self.nodes From d3cab0eecebdd74dea7f1167511155e22acafdf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Oddsson?= Date: Mon, 22 Sep 2025 15:22:20 +0000 Subject: [PATCH 19/34] Add `TOKEN_BACKTICK` to list of text content tokens (#468) This seems to fix https://github.com/marcoroth/herb/issues/467 but I might be missing some other bits and bobs --- src/parser.c | 1 + test/parser/text_content_test.rb | 4 +++ ...alid)_542130e358dadabeb4a1629bc9bcf4f3.txt | 19 ++++--------- ..._tags_6bcbe820b5902dfe97a869593621bebf.txt | 11 ++------ ...line)_372da24666282e3c531de3c5a8de44ca.txt | 11 ++------ ...e_467_f19a10dc1b4a48f5239d4125ed18cf18.txt | 28 +++++++++++++++++++ 6 files changed, 42 insertions(+), 32 deletions(-) create mode 100644 test/snapshots/parser/text_content_test/test_0033_backtick_with_HTML_tags_-_issue_467_f19a10dc1b4a48f5239d4125ed18cf18.txt diff --git a/src/parser.c b/src/parser.c index fbecd14a3..7883df5dd 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1131,6 +1131,7 @@ static void parser_parse_in_data_state(parser_T* parser, array_T* children, arra parser, TOKEN_AMPERSAND, TOKEN_AT, + TOKEN_BACKTICK, TOKEN_CHARACTER, TOKEN_COLON, TOKEN_DASH, diff --git a/test/parser/text_content_test.rb b/test/parser/text_content_test.rb index 96772573d..84e4e8d80 100644 --- a/test/parser/text_content_test.rb +++ b/test/parser/text_content_test.rb @@ -141,5 +141,9 @@ class TextContentTest < Minitest::Spec test "at symbol in attribute value" do assert_parsed_snapshot('Contact @support') end + + test "backtick with HTML tags - issue 467" do + assert_parsed_snapshot("a `` c") + end end end diff --git a/test/snapshots/parser/attributes_test/test_0037_attribute_with_backtick_containing_HTML_(invalid)_542130e358dadabeb4a1629bc9bcf4f3.txt b/test/snapshots/parser/attributes_test/test_0037_attribute_with_backtick_containing_HTML_(invalid)_542130e358dadabeb4a1629bc9bcf4f3.txt index a2749ae1a..e94501248 100644 --- a/test/snapshots/parser/attributes_test/test_0037_attribute_with_backtick_containing_HTML_(invalid)_542130e358dadabeb4a1629bc9bcf4f3.txt +++ b/test/snapshots/parser/attributes_test/test_0037_attribute_with_backtick_containing_HTML_(invalid)_542130e358dadabeb4a1629bc9bcf4f3.txt @@ -1,22 +1,10 @@ @ DocumentNode (location: (1:0)-(1:46)) -├── errors: (3 errors) -│ ├── @ UnexpectedError (location: (1:38)-(1:39)) -│ │ ├── message: "Unexpected token. Expected: `TOKEN_ERB_START, TOKEN_HTML_DOCTYPE, TOKEN_HTML_COMMENT_START, TOKEN_IDENTIFIER, TOKEN_WHITESPACE, TOKEN_NBSP, TOKEN_AT, or TOKE`, found: `TOKEN_BACKTICK`." -│ │ ├── description: "Unexpected token" -│ │ ├── expected: "TOKEN_ERB_START, TOKEN_HTML_DOCTYPE, TOKEN_HTML_COMMENT_START, TOKEN_IDENTIFIER, TOKEN_WHITESPACE, TOKEN_NBSP, TOKEN_AT, or TOKEN_NEWLINE" -│ │ └── found: "TOKEN_BACKTICK" -│ │ -│ ├── @ UnexpectedError (location: (1:39)-(1:40)) -│ │ ├── message: "Unexpected token. Expected: `TOKEN_ERB_START, TOKEN_HTML_DOCTYPE, TOKEN_HTML_COMMENT_START, TOKEN_IDENTIFIER, TOKEN_WHITESPACE, TOKEN_NBSP, TOKEN_AT, or TOKE`, found: `TOKEN_HTML_TAG_END`." -│ │ ├── description: "Unexpected token" -│ │ ├── expected: "TOKEN_ERB_START, TOKEN_HTML_DOCTYPE, TOKEN_HTML_COMMENT_START, TOKEN_IDENTIFIER, TOKEN_WHITESPACE, TOKEN_NBSP, TOKEN_AT, or TOKEN_NEWLINE" -│ │ └── found: "TOKEN_HTML_TAG_END" -│ │ +├── errors: (1 error) │ └── @ UnclosedElementError (location: (1:40)-(1:42)) │ ├── message: "Tag `
` opened at (1:1) was never closed before the end of document." │ └── opening_tag: "div" (location: (1:1)-(1:4)) │ -└── children: (2 items) +└── children: (3 items) ├── @ HTMLElementNode (location: (1:0)-(1:38)) │ ├── errors: (1 error) │ │ └── @ TagNamesMismatchError (location: (1:33)-(1:37)) @@ -89,6 +77,9 @@ │ ├── is_void: false │ └── source: "HTML" │ + ├── @ HTMLTextNode (location: (1:38)-(1:40)) + │ └── content: "`>" + │ └── @ HTMLCloseTagNode (location: (1:40)-(1:46)) ├── errors: (1 error) │ └── @ MissingOpeningTagError (location: (1:40)-(1:46)) diff --git a/test/snapshots/parser/script_style_test/test_0034_script_tag_with_template_literals_containing_closing_tags_6bcbe820b5902dfe97a869593621bebf.txt b/test/snapshots/parser/script_style_test/test_0034_script_tag_with_template_literals_containing_closing_tags_6bcbe820b5902dfe97a869593621bebf.txt index bd632c972..1a9ef0846 100644 --- a/test/snapshots/parser/script_style_test/test_0034_script_tag_with_template_literals_containing_closing_tags_6bcbe820b5902dfe97a869593621bebf.txt +++ b/test/snapshots/parser/script_style_test/test_0034_script_tag_with_template_literals_containing_closing_tags_6bcbe820b5902dfe97a869593621bebf.txt @@ -1,11 +1,4 @@ @ DocumentNode (location: (1:0)-(1:44)) -├── errors: (1 error) -│ └── @ UnexpectedError (location: (1:33)-(1:34)) -│ ├── message: "Unexpected token. Expected: `TOKEN_ERB_START, TOKEN_HTML_DOCTYPE, TOKEN_HTML_COMMENT_START, TOKEN_IDENTIFIER, TOKEN_WHITESPACE, TOKEN_NBSP, TOKEN_AT, or TOKE`, found: `TOKEN_BACKTICK`." -│ ├── description: "Unexpected token" -│ ├── expected: "TOKEN_ERB_START, TOKEN_HTML_DOCTYPE, TOKEN_HTML_COMMENT_START, TOKEN_IDENTIFIER, TOKEN_WHITESPACE, TOKEN_NBSP, TOKEN_AT, or TOKEN_NEWLINE" -│ └── found: "TOKEN_BACKTICK" -│ └── children: (3 items) ├── @ HTMLElementNode (location: (1:0)-(1:33)) │ ├── open_tag: @@ -31,8 +24,8 @@ │ ├── is_void: false │ └── source: "HTML" │ - ├── @ HTMLTextNode (location: (1:34)-(1:35)) - │ └── content: ";" + ├── @ HTMLTextNode (location: (1:33)-(1:35)) + │ └── content: "`;" │ └── @ HTMLCloseTagNode (location: (1:35)-(1:44)) ├── errors: (1 error) diff --git a/test/snapshots/parser/script_style_test/test_0053_script_tag_with_template_literal_containing_closing_tag_(multiline)_372da24666282e3c531de3c5a8de44ca.txt b/test/snapshots/parser/script_style_test/test_0053_script_tag_with_template_literal_containing_closing_tag_(multiline)_372da24666282e3c531de3c5a8de44ca.txt index 22c352d93..127bd853b 100644 --- a/test/snapshots/parser/script_style_test/test_0053_script_tag_with_template_literal_containing_closing_tag_(multiline)_372da24666282e3c531de3c5a8de44ca.txt +++ b/test/snapshots/parser/script_style_test/test_0053_script_tag_with_template_literal_containing_closing_tag_(multiline)_372da24666282e3c531de3c5a8de44ca.txt @@ -1,11 +1,4 @@ @ DocumentNode (location: (1:0)-(4:0)) -├── errors: (1 error) -│ └── @ UnexpectedError (location: (2:12)-(2:13)) -│ ├── message: "Unexpected token. Expected: `TOKEN_ERB_START, TOKEN_HTML_DOCTYPE, TOKEN_HTML_COMMENT_START, TOKEN_IDENTIFIER, TOKEN_WHITESPACE, TOKEN_NBSP, TOKEN_AT, or TOKE`, found: `TOKEN_BACKTICK`." -│ ├── description: "Unexpected token" -│ ├── expected: "TOKEN_ERB_START, TOKEN_HTML_DOCTYPE, TOKEN_HTML_COMMENT_START, TOKEN_IDENTIFIER, TOKEN_WHITESPACE, TOKEN_NBSP, TOKEN_AT, or TOKEN_NEWLINE" -│ └── found: "TOKEN_BACKTICK" -│ └── children: (4 items) ├── @ HTMLElementNode (location: (1:0)-(2:12)) │ ├── open_tag: @@ -31,8 +24,8 @@ │ ├── is_void: false │ └── source: "HTML" │ - ├── @ HTMLTextNode (location: (2:13)-(3:0)) - │ └── content: "\n" + ├── @ HTMLTextNode (location: (2:12)-(3:0)) + │ └── content: "`\n" │ ├── @ HTMLCloseTagNode (location: (3:0)-(3:9)) │ ├── errors: (1 error) diff --git a/test/snapshots/parser/text_content_test/test_0033_backtick_with_HTML_tags_-_issue_467_f19a10dc1b4a48f5239d4125ed18cf18.txt b/test/snapshots/parser/text_content_test/test_0033_backtick_with_HTML_tags_-_issue_467_f19a10dc1b4a48f5239d4125ed18cf18.txt new file mode 100644 index 000000000..ca917d5b3 --- /dev/null +++ b/test/snapshots/parser/text_content_test/test_0033_backtick_with_HTML_tags_-_issue_467_f19a10dc1b4a48f5239d4125ed18cf18.txt @@ -0,0 +1,28 @@ +@ DocumentNode (location: (1:0)-(1:13)) +└── children: (3 items) + ├── @ HTMLTextNode (location: (1:0)-(1:3)) + │ └── content: "a `" + │ + ├── @ HTMLElementNode (location: (1:3)-(1:10)) + │ ├── open_tag: + │ │ └── @ HTMLOpenTagNode (location: (1:3)-(1:6)) + │ │ ├── tag_opening: "<" (location: (1:3)-(1:4)) + │ │ ├── tag_name: "b" (location: (1:4)-(1:5)) + │ │ ├── tag_closing: ">" (location: (1:5)-(1:6)) + │ │ ├── children: [] + │ │ └── is_void: false + │ │ + │ ├── tag_name: "b" (location: (1:4)-(1:5)) + │ ├── body: [] + │ ├── close_tag: + │ │ └── @ HTMLCloseTagNode (location: (1:6)-(1:10)) + │ │ ├── tag_opening: "" (location: (1:9)-(1:10)) + │ │ + │ ├── is_void: false + │ └── source: "HTML" + │ + └── @ HTMLTextNode (location: (1:10)-(1:13)) + └── content: "` c" \ No newline at end of file From 7f3a587a26823b26789a002970891e82c1adbf27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:10:01 +0200 Subject: [PATCH 20/34] Bump the npm_and_yarn group across 1 directory with 2 updates (#516) Bumps the npm_and_yarn group with 2 updates in the / directory: [esbuild](https://github.com/evanw/esbuild) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `esbuild` from 0.25.9 to 0.25.10 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../tailwind-class-sorter/package.json | 2 +- javascript/packages/vscode/package.json | 2 +- playground/package.json | 2 +- yarn.lock | 550 +++++++++--------- 4 files changed, 284 insertions(+), 272 deletions(-) diff --git a/javascript/packages/tailwind-class-sorter/package.json b/javascript/packages/tailwind-class-sorter/package.json index 0fdd96580..3d08dde84 100644 --- a/javascript/packages/tailwind-class-sorter/package.json +++ b/javascript/packages/tailwind-class-sorter/package.json @@ -46,7 +46,7 @@ "devDependencies": { "@types/node": "^24.1.0", "dedent": "^1.6.0", - "esbuild": "^0.25.8", + "esbuild": "^0.25.10", "rimraf": "^6.0.1", "tailwindcss": "^3.4.17", "tsup": "^8.5.0", diff --git a/javascript/packages/vscode/package.json b/javascript/packages/vscode/package.json index 3d4f31e6f..f6e1db267 100644 --- a/javascript/packages/vscode/package.json +++ b/javascript/packages/vscode/package.json @@ -249,7 +249,7 @@ "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.5.2", "@vscode/vsce": "^3.5.0", - "esbuild": "^0.25.9", + "esbuild": "^0.25.10", "esbuild-plugin-copy": "^2.1.1", "eslint": "^9.25.1", "npm-run-all": "^4.1.5", diff --git a/playground/package.json b/playground/package.json index 8ba4da126..999f6ebd1 100644 --- a/playground/package.json +++ b/playground/package.json @@ -28,7 +28,7 @@ "lz-string": "^1.5.0", "monaco-editor": "^0.52.2", "prismjs": "^1.30.0", - "vite": "^6.3.6" + "vite": "^7.0.7" }, "devDependencies": { "@types/express": "^4.17.21", diff --git a/yarn.lock b/yarn.lock index 02d498018..044d9969d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -224,245 +224,245 @@ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== -"@esbuild/aix-ppc64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz#bef96351f16520055c947aba28802eede3c9e9a9" - integrity sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA== +"@esbuild/aix-ppc64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz#ee6b7163a13528e099ecf562b972f2bcebe0aa97" + integrity sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw== "@esbuild/android-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== -"@esbuild/android-arm64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz#d2e70be7d51a529425422091e0dcb90374c1546c" - integrity sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg== +"@esbuild/android-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz#115fc76631e82dd06811bfaf2db0d4979c16e2cb" + integrity sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg== "@esbuild/android-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== -"@esbuild/android-arm@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.9.tgz#d2a753fe2a4c73b79437d0ba1480e2d760097419" - integrity sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ== +"@esbuild/android-arm@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.10.tgz#8d5811912da77f615398611e5bbc1333fe321aa9" + integrity sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w== "@esbuild/android-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== -"@esbuild/android-x64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.9.tgz#5278836e3c7ae75761626962f902a0d55352e683" - integrity sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw== +"@esbuild/android-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.10.tgz#e3e96516b2d50d74105bb92594c473e30ddc16b1" + integrity sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg== "@esbuild/darwin-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== -"@esbuild/darwin-arm64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz#f1513eaf9ec8fa15dcaf4c341b0f005d3e8b47ae" - integrity sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg== +"@esbuild/darwin-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz#6af6bb1d05887dac515de1b162b59dc71212ed76" + integrity sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA== "@esbuild/darwin-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== -"@esbuild/darwin-x64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz#e27dbc3b507b3a1cea3b9280a04b8b6b725f82be" - integrity sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ== +"@esbuild/darwin-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz#99ae82347fbd336fc2d28ffd4f05694e6e5b723d" + integrity sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg== "@esbuild/freebsd-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== -"@esbuild/freebsd-arm64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz#364e3e5b7a1fd45d92be08c6cc5d890ca75908ca" - integrity sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q== +"@esbuild/freebsd-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz#0c6d5558a6322b0bdb17f7025c19bd7d2359437d" + integrity sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg== "@esbuild/freebsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== -"@esbuild/freebsd-x64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz#7c869b45faeb3df668e19ace07335a0711ec56ab" - integrity sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg== +"@esbuild/freebsd-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz#8c35873fab8c0857a75300a3dcce4324ca0b9844" + integrity sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA== "@esbuild/linux-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== -"@esbuild/linux-arm64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz#48d42861758c940b61abea43ba9a29b186d6cb8b" - integrity sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw== +"@esbuild/linux-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz#3edc2f87b889a15b4cedaf65f498c2bed7b16b90" + integrity sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ== "@esbuild/linux-arm@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== -"@esbuild/linux-arm@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz#6ce4b9cabf148274101701d112b89dc67cc52f37" - integrity sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw== +"@esbuild/linux-arm@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz#86501cfdfb3d110176d80c41b27ed4611471cde7" + integrity sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg== "@esbuild/linux-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== -"@esbuild/linux-ia32@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz#207e54899b79cac9c26c323fc1caa32e3143f1c4" - integrity sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A== +"@esbuild/linux-ia32@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz#e6589877876142537c6864680cd5d26a622b9d97" + integrity sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ== "@esbuild/linux-loong64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== -"@esbuild/linux-loong64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz#0ba48a127159a8f6abb5827f21198b999ffd1fc0" - integrity sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ== +"@esbuild/linux-loong64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz#11119e18781f136d8083ea10eb6be73db7532de8" + integrity sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg== "@esbuild/linux-mips64el@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== -"@esbuild/linux-mips64el@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz#a4d4cc693d185f66a6afde94f772b38ce5d64eb5" - integrity sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA== +"@esbuild/linux-mips64el@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz#3052f5436b0c0c67a25658d5fc87f045e7def9e6" + integrity sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA== "@esbuild/linux-ppc64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== -"@esbuild/linux-ppc64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz#0f5805c1c6d6435a1dafdc043cb07a19050357db" - integrity sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w== +"@esbuild/linux-ppc64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz#2f098920ee5be2ce799f35e367b28709925a8744" + integrity sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA== "@esbuild/linux-riscv64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== -"@esbuild/linux-riscv64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz#6776edece0f8fca79f3386398b5183ff2a827547" - integrity sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg== +"@esbuild/linux-riscv64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz#fa51d7fd0a22a62b51b4b94b405a3198cf7405dd" + integrity sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA== "@esbuild/linux-s390x@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== -"@esbuild/linux-s390x@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz#3f6f29ef036938447c2218d309dc875225861830" - integrity sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA== +"@esbuild/linux-s390x@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz#a27642e36fc282748fdb38954bd3ef4f85791e8a" + integrity sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew== "@esbuild/linux-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== -"@esbuild/linux-x64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz#831fe0b0e1a80a8b8391224ea2377d5520e1527f" - integrity sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg== +"@esbuild/linux-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz#9d9b09c0033d17529570ced6d813f98315dfe4e9" + integrity sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA== -"@esbuild/netbsd-arm64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz#06f99d7eebe035fbbe43de01c9d7e98d2a0aa548" - integrity sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q== +"@esbuild/netbsd-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz#25c09a659c97e8af19e3f2afd1c9190435802151" + integrity sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A== "@esbuild/netbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== -"@esbuild/netbsd-x64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz#db99858e6bed6e73911f92a88e4edd3a8c429a52" - integrity sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g== +"@esbuild/netbsd-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz#7fa5f6ffc19be3a0f6f5fd32c90df3dc2506937a" + integrity sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig== -"@esbuild/openbsd-arm64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz#afb886c867e36f9d86bb21e878e1185f5d5a0935" - integrity sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ== +"@esbuild/openbsd-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz#8faa6aa1afca0c6d024398321d6cb1c18e72a1c3" + integrity sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw== "@esbuild/openbsd-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== -"@esbuild/openbsd-x64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz#30855c9f8381fac6a0ef5b5f31ac6e7108a66ecf" - integrity sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA== +"@esbuild/openbsd-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz#a42979b016f29559a8453d32440d3c8cd420af5e" + integrity sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw== -"@esbuild/openharmony-arm64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz#2f2144af31e67adc2a8e3705c20c2bd97bd88314" - integrity sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg== +"@esbuild/openharmony-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz#fd87bfeadd7eeb3aa384bbba907459ffa3197cb1" + integrity sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag== "@esbuild/sunos-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== -"@esbuild/sunos-x64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz#69b99a9b5bd226c9eb9c6a73f990fddd497d732e" - integrity sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw== +"@esbuild/sunos-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz#3a18f590e36cb78ae7397976b760b2b8c74407f4" + integrity sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ== "@esbuild/win32-arm64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== -"@esbuild/win32-arm64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz#d789330a712af916c88325f4ffe465f885719c6b" - integrity sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ== +"@esbuild/win32-arm64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz#e71741a251e3fd971408827a529d2325551f530c" + integrity sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw== "@esbuild/win32-ia32@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== -"@esbuild/win32-ia32@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz#52fc735406bd49688253e74e4e837ac2ba0789e3" - integrity sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww== +"@esbuild/win32-ia32@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz#c6f010b5d3b943d8901a0c87ea55f93b8b54bf94" + integrity sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw== "@esbuild/win32-x64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== -"@esbuild/win32-x64@0.25.9": - version "0.25.9" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz#585624dc829cfb6e7c0aa6c3ca7d7e6daa87e34f" - integrity sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ== +"@esbuild/win32-x64@0.25.10": + version "0.25.10" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz#e4b3e255a1b4aea84f6e1d2ae0b73f826c3785bd" + integrity sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.7.0": version "4.7.0" @@ -1297,105 +1297,115 @@ estree-walker "^2.0.2" picomatch "^4.0.2" -"@rollup/rollup-android-arm-eabi@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.49.0.tgz#ba432433f5e7b419dba2be407d1d59fea6b8de48" - integrity sha512-rlKIeL854Ed0e09QGYFlmDNbka6I3EQFw7iZuugQjMb11KMpJCLPFL4ZPbMfaEhLADEL1yx0oujGkBQ7+qW3eA== - -"@rollup/rollup-android-arm64@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.49.0.tgz#4e05c86e0fb9af6eaf52fc298dcdec577477e35c" - integrity sha512-cqPpZdKUSQYRtLLr6R4X3sD4jCBO1zUmeo3qrWBCqYIeH8Q3KRL4F3V7XJ2Rm8/RJOQBZuqzQGWPjjvFUcYa/w== - -"@rollup/rollup-darwin-arm64@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.49.0.tgz#788fad425b4129875639e0c14b6441c5f3b69d46" - integrity sha512-99kMMSMQT7got6iYX3yyIiJfFndpojBmkHfTc1rIje8VbjhmqBXE+nb7ZZP3A5skLyujvT0eIUCUsxAe6NjWbw== - -"@rollup/rollup-darwin-x64@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.49.0.tgz#d44e05bee55b781d7c2cf535d9f9169787c3599d" - integrity sha512-y8cXoD3wdWUDpjOLMKLx6l+NFz3NlkWKcBCBfttUn+VGSfgsQ5o/yDUGtzE9HvsodkP0+16N0P4Ty1VuhtRUGg== - -"@rollup/rollup-freebsd-arm64@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.49.0.tgz#107786b4d604495224c3543bfd2cae33ddf76500" - integrity sha512-3mY5Pr7qv4GS4ZvWoSP8zha8YoiqrU+e0ViPvB549jvliBbdNLrg2ywPGkgLC3cmvN8ya3za+Q2xVyT6z+vZqA== - -"@rollup/rollup-freebsd-x64@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.49.0.tgz#54e105c3da27f31084ca6913fed603627755abde" - integrity sha512-C9KzzOAQU5gU4kG8DTk+tjdKjpWhVWd5uVkinCwwFub2m7cDYLOdtXoMrExfeBmeRy9kBQMkiyJ+HULyF1yj9w== - -"@rollup/rollup-linux-arm-gnueabihf@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.49.0.tgz#725c23e0766b5d9368180bc2c427a51e31d0e147" - integrity sha512-OVSQgEZDVLnTbMq5NBs6xkmz3AADByCWI4RdKSFNlDsYXdFtlxS59J+w+LippJe8KcmeSSM3ba+GlsM9+WwC1w== - -"@rollup/rollup-linux-arm-musleabihf@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.49.0.tgz#6946b0d2f132f2baf5657945b81565d8abd51cc0" - integrity sha512-ZnfSFA7fDUHNa4P3VwAcfaBLakCbYaxCk0jUnS3dTou9P95kwoOLAMlT3WmEJDBCSrOEFFV0Y1HXiwfLYJuLlA== - -"@rollup/rollup-linux-arm64-gnu@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.49.0.tgz#83510a6d03e748619241a17f5a879418a963c5ed" - integrity sha512-Z81u+gfrobVK2iV7GqZCBfEB1y6+I61AH466lNK+xy1jfqFLiQ9Qv716WUM5fxFrYxwC7ziVdZRU9qvGHkYIJg== - -"@rollup/rollup-linux-arm64-musl@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.49.0.tgz#085b98d44c10908626dd40f26bf924433bbd8471" - integrity sha512-zoAwS0KCXSnTp9NH/h9aamBAIve0DXeYpll85shf9NJ0URjSTzzS+Z9evmolN+ICfD3v8skKUPyk2PO0uGdFqg== - -"@rollup/rollup-linux-loongarch64-gnu@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.49.0.tgz#13e0a4808e9f7924f2cc8c133603f627c7a00543" - integrity sha512-2QyUyQQ1ZtwZGiq0nvODL+vLJBtciItC3/5cYN8ncDQcv5avrt2MbKt1XU/vFAJlLta5KujqyHdYtdag4YEjYQ== - -"@rollup/rollup-linux-ppc64-gnu@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.49.0.tgz#aeee4e47fc9ca5d6687e686fea4696202af6b2f4" - integrity sha512-k9aEmOWt+mrMuD3skjVJSSxHckJp+SiFzFG+v8JLXbc/xi9hv2icSkR3U7uQzqy+/QbbYY7iNB9eDTwrELo14g== - -"@rollup/rollup-linux-riscv64-gnu@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.49.0.tgz#603e4591643f1d7851a96d096cf7fcd273f7b0e1" - integrity sha512-rDKRFFIWJ/zJn6uk2IdYLc09Z7zkE5IFIOWqpuU0o6ZpHcdniAyWkwSUWE/Z25N/wNDmFHHMzin84qW7Wzkjsw== - -"@rollup/rollup-linux-riscv64-musl@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.49.0.tgz#f8fd9b01f1888e1816d5a398789d430511286c00" - integrity sha512-FkkhIY/hYFVnOzz1WeV3S9Bd1h0hda/gRqvZCMpHWDHdiIHn6pqsY3b5eSbvGccWHMQ1uUzgZTKS4oGpykf8Tw== - -"@rollup/rollup-linux-s390x-gnu@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.49.0.tgz#37a1fd372d9b93d2b75b2f37c482ecf52f52849b" - integrity sha512-gRf5c+A7QiOG3UwLyOOtyJMD31JJhMjBvpfhAitPAoqZFcOeK3Kc1Veg1z/trmt+2P6F/biT02fU19GGTS529A== - -"@rollup/rollup-linux-x64-gnu@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.49.0.tgz#131e66dbf7e71cb2a389acc45319bd4c990e093a" - integrity sha512-BR7+blScdLW1h/2hB/2oXM+dhTmpW3rQt1DeSiCP9mc2NMMkqVgjIN3DDsNpKmezffGC9R8XKVOLmBkRUcK/sA== - -"@rollup/rollup-linux-x64-musl@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.49.0.tgz#b7245a5ea57db9679e8bf3032c25a5d2c5f54056" - integrity sha512-hDMOAe+6nX3V5ei1I7Au3wcr9h3ktKzDvF2ne5ovX8RZiAHEtX1A5SNNk4zt1Qt77CmnbqT+upb/umzoPMWiPg== - -"@rollup/rollup-win32-arm64-msvc@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.49.0.tgz#768a128bb5da3c5472c3c56aec77507d28bc7209" - integrity sha512-wkNRzfiIGaElC9kXUT+HLx17z7D0jl+9tGYRKwd8r7cUqTL7GYAvgUY++U2hK6Ar7z5Z6IRRoWC8kQxpmM7TDA== - -"@rollup/rollup-win32-ia32-msvc@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.49.0.tgz#ce3f3b2eebe585340631498666718f00983a6a62" - integrity sha512-gq5aW/SyNpjp71AAzroH37DtINDcX1Qw2iv9Chyz49ZgdOP3NV8QCyKZUrGsYX9Yyggj5soFiRCgsL3HwD8TdA== - -"@rollup/rollup-win32-x64-msvc@4.49.0": - version "4.49.0" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.49.0.tgz#c2a0e3b81262a7e9dd12ce18b350a97558dd50bc" - integrity sha512-gEtqFbzmZLFk2xKh7g0Rlo8xzho8KrEFEkzvHbfUGkrgXOpZ4XagQ6n+wIZFNh1nTb8UD16J4nFSFKXYgnbdBg== +"@rollup/rollup-android-arm-eabi@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.0.tgz#dfcddfa85a3cba8a0e95483b4a7255ab9e4cdf4d" + integrity sha512-VxDYCDqOaR7NXzAtvRx7G1u54d2kEHopb28YH/pKzY6y0qmogP3gG7CSiWsq9WvDFxOQMpNEyjVAHZFXfH3o/A== + +"@rollup/rollup-android-arm64@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.0.tgz#f37b4a8741a7f42d2f2921bd621e7e824a262f0c" + integrity sha512-pqDirm8koABIKvzL59YI9W9DWbRlTX7RWhN+auR8HXJxo89m4mjqbah7nJZjeKNTNYopqL+yGg+0mhCpf3xZtQ== + +"@rollup/rollup-darwin-arm64@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.0.tgz#fda8701d38d9888039c1a0e040c026daec908a3f" + integrity sha512-YCdWlY/8ltN6H78HnMsRHYlPiKvqKagBP1r+D7SSylxX+HnsgXGCmLiV3Y4nSyY9hW8qr8U9LDUx/Lo7M6MfmQ== + +"@rollup/rollup-darwin-x64@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.0.tgz#c6008839852a33a686080957d296f727af9ca80d" + integrity sha512-z4nw6y1j+OOSGzuVbSWdIp1IUks9qNw4dc7z7lWuWDKojY38VMWBlEN7F9jk5UXOkUcp97vA1N213DF+Lz8BRg== + +"@rollup/rollup-freebsd-arm64@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.0.tgz#2b3ee9028493fd58245ded2137de0bc5d6b8f1e4" + integrity sha512-Q/dv9Yvyr5rKlK8WQJZVrp5g2SOYeZUs9u/t2f9cQ2E0gJjYB/BWoedXfUT0EcDJefi2zzVfhcOj8drWCzTviw== + +"@rollup/rollup-freebsd-x64@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.0.tgz#32e1ed194ceb3e0ef204efa237c04db13dece948" + integrity sha512-kdBsLs4Uile/fbjZVvCRcKB4q64R+1mUq0Yd7oU1CMm1Av336ajIFqNFovByipciuUQjBCPMxwJhCgfG2re3rg== + +"@rollup/rollup-linux-arm-gnueabihf@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.0.tgz#e64b1b7b2744803d7f52701f8bbd2989ae399424" + integrity sha512-aL6hRwu0k7MTUESgkg7QHY6CoqPgr6gdQXRJI1/VbFlUMwsSzPGSR7sG5d+MCbYnJmJwThc2ol3nixj1fvI/zQ== + +"@rollup/rollup-linux-arm-musleabihf@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.0.tgz#cef6569f633cacd09ad89189b9a805067141e01f" + integrity sha512-BTs0M5s1EJejgIBJhCeiFo7GZZ2IXWkFGcyZhxX4+8usnIo5Mti57108vjXFIQmmJaRyDwmV59Tw64Ap1dkwMw== + +"@rollup/rollup-linux-arm64-gnu@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.0.tgz#358c20dc375f80e20048f99f46b507d6d8063fdf" + integrity sha512-uj672IVOU9m08DBGvoPKPi/J8jlVgjh12C9GmjjBxCTQc3XtVmRkRKyeHSmIKQpvJ7fIm1EJieBUcnGSzDVFyw== + +"@rollup/rollup-linux-arm64-musl@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.0.tgz#8141352ddffbf4200b464c1e1957c050f5c0842a" + integrity sha512-/+IVbeDMDCtB/HP/wiWsSzduD10SEGzIZX2945KSgZRNi4TSkjHqRJtNTVtVb8IRwhJ65ssI56krlLik+zFWkw== + +"@rollup/rollup-linux-loong64-gnu@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.0.tgz#d92ac6909a29c9f3793e12fdd826d81a0eef0966" + integrity sha512-U1vVzvSWtSMWKKrGoROPBXMh3Vwn93TA9V35PldokHGqiUbF6erSzox/5qrSMKp6SzakvyjcPiVF8yB1xKr9Pg== + +"@rollup/rollup-linux-ppc64-gnu@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.0.tgz#01aacb8e24c41fc5bed2d592c34c210e92975cd3" + integrity sha512-X/4WfuBAdQRH8cK3DYl8zC00XEE6aM472W+QCycpQJeLWVnHfkv7RyBFVaTqNUMsTgIX8ihMjCvFF9OUgeABzw== + +"@rollup/rollup-linux-riscv64-gnu@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.0.tgz#fe3224c04b005a378b22f53f3be718c6c175d782" + integrity sha512-xIRYc58HfWDBZoLmWfWXg2Sq8VCa2iJ32B7mqfWnkx5mekekl0tMe7FHpY8I72RXEcUkaWawRvl3qA55og+cwQ== + +"@rollup/rollup-linux-riscv64-musl@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.0.tgz#ff25daa05f99c77f43e4d8eef02d57c231dac6ed" + integrity sha512-mbsoUey05WJIOz8U1WzNdf+6UMYGwE3fZZnQqsM22FZ3wh1N887HT6jAOjXs6CNEK3Ntu2OBsyQDXfIjouI4dw== + +"@rollup/rollup-linux-s390x-gnu@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.0.tgz#7afac92ea34b129e1430351f615b9f6a84f6510d" + integrity sha512-qP6aP970bucEi5KKKR4AuPFd8aTx9EF6BvutvYxmZuWLJHmnq4LvBfp0U+yFDMGwJ+AIJEH5sIP+SNypauMWzg== + +"@rollup/rollup-linux-x64-gnu@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.0.tgz#214b534701614c7502603e2a083bb9f072ae8500" + integrity sha512-nmSVN+F2i1yKZ7rJNKO3G7ZzmxJgoQBQZ/6c4MuS553Grmr7WqR7LLDcYG53Z2m9409z3JLt4sCOhLdbKQ3HmA== + +"@rollup/rollup-linux-x64-musl@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.0.tgz#8bdc313319fb097795b9213782354afeb8452658" + integrity sha512-2d0qRo33G6TfQVjaMR71P+yJVGODrt5V6+T0BDYH4EMfGgdC/2HWDVjSSFw888GSzAZUwuska3+zxNUCDco6rQ== + +"@rollup/rollup-openharmony-arm64@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.0.tgz#3a6050fc85143f14039c2e8f8f6e90e9e60a392c" + integrity sha512-A1JalX4MOaFAAyGgpO7XP5khquv/7xKzLIyLmhNrbiCxWpMlnsTYr8dnsWM7sEeotNmxvSOEL7F65j0HXFcFsw== + +"@rollup/rollup-win32-arm64-msvc@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.0.tgz#7a57e55beeb598b7a27786e95142f39fff5daddb" + integrity sha512-YQugafP/rH0eOOHGjmNgDURrpYHrIX0yuojOI8bwCyXwxC9ZdTd3vYkmddPX0oHONLXu9Rb1dDmT0VNpjkzGGw== + +"@rollup/rollup-win32-ia32-msvc@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.0.tgz#a7a7a1b5d53bd3fdddf494106961c018a39f6f77" + integrity sha512-zYdUYhi3Qe2fndujBqL5FjAFzvNeLxtIqfzNEVKD1I7C37/chv1VxhscWSQHTNfjPCrBFQMnynwA3kpZpZ8w4A== + +"@rollup/rollup-win32-x64-gnu@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.0.tgz#45040d6623b0db5dd3b9ee0054708ba8b25cd787" + integrity sha512-fGk03kQylNaCOQ96HDMeT7E2n91EqvCDd3RwvT5k+xNdFCeMGnj5b5hEgTGrQuyidqSsD3zJDQ21QIaxXqTBJw== + +"@rollup/rollup-win32-x64-msvc@4.52.0": + version "4.52.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.0.tgz#79bc6c361bd80134402274e7c4a6bb36c88d50c2" + integrity sha512-6iKDCVSIUQ8jPMoIV0OytRKniaYyy5EbY/RRydmLW8ZR3cEBhxbWl5ro0rkUNe0ef6sScvhbY79HrjRm8i3vDQ== "@secretlint/config-creator@^10.2.2": version "10.2.2" @@ -4238,37 +4248,37 @@ esbuild@^0.21.3: "@esbuild/win32-ia32" "0.21.5" "@esbuild/win32-x64" "0.21.5" -esbuild@^0.25.0, esbuild@^0.25.8, esbuild@^0.25.9, esbuild@~0.25.0: - version "0.25.9" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.9.tgz#15ab8e39ae6cdc64c24ff8a2c0aef5b3fd9fa976" - integrity sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g== +esbuild@^0.25.0, esbuild@^0.25.10, esbuild@~0.25.0: + version "0.25.10" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.10.tgz#37f5aa5cd14500f141be121c01b096ca83ac34a9" + integrity sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ== optionalDependencies: - "@esbuild/aix-ppc64" "0.25.9" - "@esbuild/android-arm" "0.25.9" - "@esbuild/android-arm64" "0.25.9" - "@esbuild/android-x64" "0.25.9" - "@esbuild/darwin-arm64" "0.25.9" - "@esbuild/darwin-x64" "0.25.9" - "@esbuild/freebsd-arm64" "0.25.9" - "@esbuild/freebsd-x64" "0.25.9" - "@esbuild/linux-arm" "0.25.9" - "@esbuild/linux-arm64" "0.25.9" - "@esbuild/linux-ia32" "0.25.9" - "@esbuild/linux-loong64" "0.25.9" - "@esbuild/linux-mips64el" "0.25.9" - "@esbuild/linux-ppc64" "0.25.9" - "@esbuild/linux-riscv64" "0.25.9" - "@esbuild/linux-s390x" "0.25.9" - "@esbuild/linux-x64" "0.25.9" - "@esbuild/netbsd-arm64" "0.25.9" - "@esbuild/netbsd-x64" "0.25.9" - "@esbuild/openbsd-arm64" "0.25.9" - "@esbuild/openbsd-x64" "0.25.9" - "@esbuild/openharmony-arm64" "0.25.9" - "@esbuild/sunos-x64" "0.25.9" - "@esbuild/win32-arm64" "0.25.9" - "@esbuild/win32-ia32" "0.25.9" - "@esbuild/win32-x64" "0.25.9" + "@esbuild/aix-ppc64" "0.25.10" + "@esbuild/android-arm" "0.25.10" + "@esbuild/android-arm64" "0.25.10" + "@esbuild/android-x64" "0.25.10" + "@esbuild/darwin-arm64" "0.25.10" + "@esbuild/darwin-x64" "0.25.10" + "@esbuild/freebsd-arm64" "0.25.10" + "@esbuild/freebsd-x64" "0.25.10" + "@esbuild/linux-arm" "0.25.10" + "@esbuild/linux-arm64" "0.25.10" + "@esbuild/linux-ia32" "0.25.10" + "@esbuild/linux-loong64" "0.25.10" + "@esbuild/linux-mips64el" "0.25.10" + "@esbuild/linux-ppc64" "0.25.10" + "@esbuild/linux-riscv64" "0.25.10" + "@esbuild/linux-s390x" "0.25.10" + "@esbuild/linux-x64" "0.25.10" + "@esbuild/netbsd-arm64" "0.25.10" + "@esbuild/netbsd-x64" "0.25.10" + "@esbuild/openbsd-arm64" "0.25.10" + "@esbuild/openbsd-x64" "0.25.10" + "@esbuild/openharmony-arm64" "0.25.10" + "@esbuild/sunos-x64" "0.25.10" + "@esbuild/win32-arm64" "0.25.10" + "@esbuild/win32-ia32" "0.25.10" + "@esbuild/win32-x64" "0.25.10" escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" @@ -4581,7 +4591,7 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -fdir@^6.2.0, fdir@^6.4.4, fdir@^6.5.0: +fdir@^6.2.0, fdir@^6.4.4, fdir@^6.4.6, fdir@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== @@ -8159,7 +8169,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.43, postcss@^8.4.47, postcss@^8.5.3, postcss@^8.5.6: +postcss@^8.4.43, postcss@^8.4.47, postcss@^8.5.6: version "8.5.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== @@ -8656,33 +8666,35 @@ rollup-pluginutils@^2.8.2: dependencies: estree-walker "^0.6.1" -rollup@^4.20.0, rollup@^4.34.8, rollup@^4.34.9, rollup@^4.43.0, rollup@^4.47.1: - version "4.49.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.49.0.tgz#9751ad9d06a47a4496c3c5c238b27b1422c8b0eb" - integrity sha512-3IVq0cGJ6H7fKXXEdVt+RcYvRCt8beYY9K1760wGQwSAHZcS9eot1zDG5axUbcp/kWRi5zKIIDX8MoKv/TzvZA== +rollup@^4.20.0, rollup@^4.34.8, rollup@^4.40.0, rollup@^4.43.0, rollup@^4.47.1: + version "4.52.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.52.0.tgz#5a906bf98f7c7a2c08d2b18fbfa52955552423d7" + integrity sha512-+IuescNkTJQgX7AkIDtITipZdIGcWF0pnVvZTWStiazUmcGA2ag8dfg0urest2XlXUi9kuhfQ+qmdc5Stc3z7g== dependencies: "@types/estree" "1.0.8" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.49.0" - "@rollup/rollup-android-arm64" "4.49.0" - "@rollup/rollup-darwin-arm64" "4.49.0" - "@rollup/rollup-darwin-x64" "4.49.0" - "@rollup/rollup-freebsd-arm64" "4.49.0" - "@rollup/rollup-freebsd-x64" "4.49.0" - "@rollup/rollup-linux-arm-gnueabihf" "4.49.0" - "@rollup/rollup-linux-arm-musleabihf" "4.49.0" - "@rollup/rollup-linux-arm64-gnu" "4.49.0" - "@rollup/rollup-linux-arm64-musl" "4.49.0" - "@rollup/rollup-linux-loongarch64-gnu" "4.49.0" - "@rollup/rollup-linux-ppc64-gnu" "4.49.0" - "@rollup/rollup-linux-riscv64-gnu" "4.49.0" - "@rollup/rollup-linux-riscv64-musl" "4.49.0" - "@rollup/rollup-linux-s390x-gnu" "4.49.0" - "@rollup/rollup-linux-x64-gnu" "4.49.0" - "@rollup/rollup-linux-x64-musl" "4.49.0" - "@rollup/rollup-win32-arm64-msvc" "4.49.0" - "@rollup/rollup-win32-ia32-msvc" "4.49.0" - "@rollup/rollup-win32-x64-msvc" "4.49.0" + "@rollup/rollup-android-arm-eabi" "4.52.0" + "@rollup/rollup-android-arm64" "4.52.0" + "@rollup/rollup-darwin-arm64" "4.52.0" + "@rollup/rollup-darwin-x64" "4.52.0" + "@rollup/rollup-freebsd-arm64" "4.52.0" + "@rollup/rollup-freebsd-x64" "4.52.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.52.0" + "@rollup/rollup-linux-arm-musleabihf" "4.52.0" + "@rollup/rollup-linux-arm64-gnu" "4.52.0" + "@rollup/rollup-linux-arm64-musl" "4.52.0" + "@rollup/rollup-linux-loong64-gnu" "4.52.0" + "@rollup/rollup-linux-ppc64-gnu" "4.52.0" + "@rollup/rollup-linux-riscv64-gnu" "4.52.0" + "@rollup/rollup-linux-riscv64-musl" "4.52.0" + "@rollup/rollup-linux-s390x-gnu" "4.52.0" + "@rollup/rollup-linux-x64-gnu" "4.52.0" + "@rollup/rollup-linux-x64-musl" "4.52.0" + "@rollup/rollup-openharmony-arm64" "4.52.0" + "@rollup/rollup-win32-arm64-msvc" "4.52.0" + "@rollup/rollup-win32-ia32-msvc" "4.52.0" + "@rollup/rollup-win32-x64-gnu" "4.52.0" + "@rollup/rollup-win32-x64-msvc" "4.52.0" fsevents "~2.3.2" router@^2.2.0: @@ -9620,7 +9632,7 @@ tinyexec@^1.0.1: resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1" integrity sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw== -tinyglobby@^0.2.11, tinyglobby@^0.2.13, tinyglobby@^0.2.14: +tinyglobby@^0.2.11, tinyglobby@^0.2.14: version "0.2.14" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== @@ -10171,17 +10183,17 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -vite@^6.3.6: - version "6.3.6" - resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.6.tgz#69a976b64930750d40219fbc68c5200874d315c1" - integrity sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA== +vite@^7.0.7: + version "7.0.7" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.0.7.tgz#d883a0297d24139237676f4227ac2b1e72f9677b" + integrity sha512-hc6LujN/EkJHmxeiDJMs0qBontZ1cdBvvoCbWhVjzUFTU329VRyOC46gHNSA8NcOC5yzCeXpwI40tieI3DEZqg== dependencies: esbuild "^0.25.0" - fdir "^6.4.4" - picomatch "^4.0.2" - postcss "^8.5.3" - rollup "^4.34.9" - tinyglobby "^0.2.13" + fdir "^6.4.6" + picomatch "^4.0.3" + postcss "^8.5.6" + rollup "^4.40.0" + tinyglobby "^0.2.14" optionalDependencies: fsevents "~2.3.3" From 3ab0155f8fd9bbc74273a2822f671a179b8ae044 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Mon, 22 Sep 2025 17:16:31 +0100 Subject: [PATCH 21/34] Parser: Don't treat guard clauses as `ERBIfNode` or `ERBUnlessNode` (#517) This pull request updates the parser and the analyzer to only transform an `ERBContentNode` node to an `ERBIfNode` or `ERBUnlessNode` when it has both `if/unless` and `end` keywords. Guard clauses or ternaries shouldn't be treated as `ERBIfNode` or `ERBUnlessNode`. We might want to revisit this when we expose the actual prism nodes for each `ERBContentNode`, but for the sake of parsing/formatting we shouldn't treat those `ERBIfNode` or `ERBUnlessNode` nodes for now. Resolves #505 --- .../packages/formatter/test/erb/if.test.ts | 129 ++++++++++++ .../formatter/test/erb/unless.test.ts | 185 ++++++++++++++++++ src/analyze_helpers.c | 23 ++- test/analyze/if_test.rb | 27 +++ test/analyze/unless_test.rb | 51 +++++ ...fNode_84c50d0087a29c69bf5125ce6ec79f86.txt | 53 +++++ ...ifier_6a92e7d29b0b8ff99771a96e90f4ac10.txt | 58 ++++++ ...ifier_41f095a3d010c4b7e9a38aa708b9054d.txt | 56 ++++++ ...sNode_647968bffc9de35b805b872472b322b7.txt | 60 ++++++ ...ifier_650bfc3134fa92038c335f96f9047860.txt | 58 ++++++ ...ifier_5ae9786a5b6893828c737287cffd216f.txt | 56 ++++++ ...auses_80edd1ae63fb2cd18f33418d1ef308c1.txt | 80 ++++++++ ...nless_4ca85acaceb3fb39b75797c6a07e7437.txt | 159 +++++++++++++++ 13 files changed, 989 insertions(+), 6 deletions(-) create mode 100644 test/snapshots/analyze/if_test/test_0010_guard_clause_with_if_modifier_should_not_be_parsed_as_ERBIfNode_84c50d0087a29c69bf5125ce6ec79f86.txt create mode 100644 test/snapshots/analyze/if_test/test_0011_guard_clause_with_return_if_modifier_6a92e7d29b0b8ff99771a96e90f4ac10.txt create mode 100644 test/snapshots/analyze/if_test/test_0012_guard_clause_with_break_if_modifier_41f095a3d010c4b7e9a38aa708b9054d.txt create mode 100644 test/snapshots/analyze/unless_test/test_0007_guard_clause_with_unless_modifier_should_not_be_parsed_as_ERBUnlessNode_647968bffc9de35b805b872472b322b7.txt create mode 100644 test/snapshots/analyze/unless_test/test_0008_guard_clause_with_return_unless_modifier_650bfc3134fa92038c335f96f9047860.txt create mode 100644 test/snapshots/analyze/unless_test/test_0009_guard_clause_with_break_unless_modifier_5ae9786a5b6893828c737287cffd216f.txt create mode 100644 test/snapshots/analyze/unless_test/test_0010_multiple_unless_guard_clauses_80edd1ae63fb2cd18f33418d1ef308c1.txt create mode 100644 test/snapshots/analyze/unless_test/test_0011_distinguishes_between_block_unless_and_modifier_unless_4ca85acaceb3fb39b75797c6a07e7437.txt diff --git a/javascript/packages/formatter/test/erb/if.test.ts b/javascript/packages/formatter/test/erb/if.test.ts index 16726f7fa..6be5b062a 100644 --- a/javascript/packages/formatter/test/erb/if.test.ts +++ b/javascript/packages/formatter/test/erb/if.test.ts @@ -126,4 +126,133 @@ describe("@herb-tools/formatter", () => { const output = formatter.format(input) expect(output).toEqual(expected) }) + + describe("guard clauses (modifier if)", () => { + test("does not indent content after 'next if' guard clause", () => { + const input = dedent` + <% [1,2].each do |value| %> + <% next if false %> +
+ <% end %> + ` + + const expected = dedent` + <% [1,2].each do |value| %> + <% next if false %> +
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("does not indent content after 'return if' guard clause", () => { + const input = dedent` + <% (1..10).each do %> + <% return if condition %> +
Content
+

More content

+ <% end %> + ` + + const expected = dedent` + <% (1..10).each do %> + <% return if condition %> +
Content
+ +

More content

+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("does not indent content after 'break if' guard clause", () => { + const input = dedent` + <% loop do %> + <% break if done %> +
Loop content
+ <% end %> + ` + + const expected = dedent` + <% loop do %> + <% break if done %> +
Loop content
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("handles multiple guard clauses in sequence", () => { + const input = dedent` + <% items.each do |item| %> + <% next if item.nil? %> + <% next if item.hidden? %> +
<%= item.name %>
+ <% end %> + ` + + const expected = dedent` + <% items.each do |item| %> + <% next if item.nil? %> + <% next if item.hidden? %> +
<%= item.name %>
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("handles guard clause with unless modifier", () => { + const input = dedent` + <% items.each do |item| %> + <% next unless item.visible? %> +
<%= item.name %>
+ <% end %> + ` + + const expected = dedent` + <% items.each do |item| %> + <% next unless item.visible? %> +
<%= item.name %>
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("distinguishes between block if and modifier if", () => { + const input = dedent` + <% items.each do |item| %> + <% next if item.skip? %> + <% if item.special? %> +
<%= item.name %>
+ <% else %> +
<%= item.name %>
+ <% end %> + <% end %> + ` + + const expected = dedent` + <% items.each do |item| %> + <% next if item.skip? %> + <% if item.special? %> +
<%= item.name %>
+ <% else %> +
<%= item.name %>
+ <% end %> + <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + }) }) diff --git a/javascript/packages/formatter/test/erb/unless.test.ts b/javascript/packages/formatter/test/erb/unless.test.ts index ac4d4e5c3..1f707f458 100644 --- a/javascript/packages/formatter/test/erb/unless.test.ts +++ b/javascript/packages/formatter/test/erb/unless.test.ts @@ -119,4 +119,189 @@ describe("@herb-tools/formatter", () => { const output = formatter.format(input) expect(output).toEqual(expected) }) + + describe("guard clauses (modifier unless)", () => { + test("does not indent content after 'next unless' guard clause", () => { + const input = dedent` + <% items.each do |item| %> + <% next unless item.visible? %> +
<%= item.name %>
+ <% end %> + ` + + const expected = dedent` + <% items.each do |item| %> + <% next unless item.visible? %> +
<%= item.name %>
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("does not indent content after 'return unless' guard clause", () => { + const input = dedent` + <% [1, 2].each do %> + <% return unless @content.present? %> +
+ <%= @content %> +
+ <% end %> + ` + + const expected = dedent` + <% [1, 2].each do %> + <% return unless @content.present? %> +
<%= @content %>
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("does not indent content after 'break unless' guard clause", () => { + const input = dedent` + <% loop do %> + <% break unless continue_processing? %> +
Processing...
+ <% end %> + ` + + const expected = dedent` + <% loop do %> + <% break unless continue_processing? %> +
Processing...
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("handles multiple unless guard clauses in sequence", () => { + const input = dedent` + <% items.each do |item| %> + <% next unless item %> + <% next unless item.active? %> + <% next unless item.published? %> +
+

<%= item.title %>

+

<%= item.description %>

+
+ <% end %> + ` + + const expected = dedent` + <% items.each do |item| %> + <% next unless item %> + <% next unless item.active? %> + <% next unless item.published? %> +
+

<%= item.title %>

+

<%= item.description %>

+
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("distinguishes between block unless and modifier unless", () => { + const input = dedent` + <% items.each do |item| %> + <% next unless item.visible? %> + <% unless item.featured? %> +
+ <%= item.name %> +
+ <% else %> + + <% end %> + <% end %> + ` + + const expected = dedent` + <% items.each do |item| %> + <% next unless item.visible? %> + <% unless item.featured? %> +
<%= item.name %>
+ <% else %> + + <% end %> + <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("handles mixed if and unless modifiers", () => { + const input = dedent` + <% products.each do |product| %> + <% next if product.discontinued? %> + <% next unless product.in_stock? %> + <% next if product.price > budget %> + <% next unless product.available_in_region? %> +
+

<%= product.name %>

+ $<%= product.price %> +
+ <% end %> + ` + + const expected = dedent` + <% products.each do |product| %> + <% next if product.discontinued? %> + <% next unless product.in_stock? %> + <% next if product.price > budget %> + <% next unless product.available_in_region? %> +
+

<%= product.name %>

+ $<%= product.price %> +
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + + test("handles guard clauses in nested blocks", () => { + const input = dedent` + <% categories.each do |category| %> + <% next unless category.active? %> +
+

<%= category.name %>

+ <% category.items.each do |item| %> + <% next if item.hidden? %> + <% next unless item.published? %> +
<%= item.title %>
+ <% end %> +
+ <% end %> + ` + + const expected = dedent` + <% categories.each do |category| %> + <% next unless category.active? %> +
+

<%= category.name %>

+ <% category.items.each do |item| %> + <% next if item.hidden? %> + <% next unless item.published? %> +
<%= item.title %>
+ <% end %> +
+ <% end %> + ` + + const output = formatter.format(input) + expect(output).toEqual(expected) + }) + }) }) diff --git a/src/analyze_helpers.c b/src/analyze_helpers.c index 6709c0267..576a10b9d 100644 --- a/src/analyze_helpers.c +++ b/src/analyze_helpers.c @@ -91,9 +91,12 @@ bool search_if_nodes(const pm_node_t* node, void* data) { if (node->type == PM_IF_NODE) { const pm_if_node_t* if_node = (const pm_if_node_t*) node; - // Handle ternary - if (if_node->if_keyword_loc.start != NULL && if_node->if_keyword_loc.end != NULL) { + bool has_if_keyword = if_node->if_keyword_loc.start != NULL && if_node->if_keyword_loc.end != NULL; + bool has_end_keyword = if_node->end_keyword_loc.start != NULL && if_node->end_keyword_loc.end != NULL; + + if (has_if_keyword && has_end_keyword) { analyzed->has_if_node = true; + return true; } } @@ -198,12 +201,20 @@ bool search_unless_nodes(const pm_node_t* node, void* data) { analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data; if (node->type == PM_UNLESS_NODE) { - analyzed->has_unless_node = true; - return true; - } else { - pm_visit_child_nodes(node, search_unless_nodes, analyzed); + const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node; + + bool has_if_keyword = unless_node->keyword_loc.start != NULL && unless_node->keyword_loc.end != NULL; + bool has_end_keyword = unless_node->end_keyword_loc.start != NULL && unless_node->end_keyword_loc.end != NULL; + + if (has_if_keyword && has_end_keyword) { + analyzed->has_unless_node = true; + + return true; + } } + pm_visit_child_nodes(node, search_unless_nodes, analyzed); + return false; } diff --git a/test/analyze/if_test.rb b/test/analyze/if_test.rb index 5841c795f..dc890e23e 100644 --- a/test/analyze/if_test.rb +++ b/test/analyze/if_test.rb @@ -93,5 +93,32 @@ class IfTest < Minitest::Spec

HTML end + + test "guard clause with if modifier should not be parsed as ERBIfNode" do + assert_parsed_snapshot(<<~HTML) + <% [1,2].each do |value| %> + <% next if false %> +
+ <% end %> + HTML + end + + test "guard clause with return if modifier" do + assert_parsed_snapshot(<<~HTML) + <% def some_method %> + <% return if true %> +
This won't render
+ <% end %> + HTML + end + + test "guard clause with break if modifier" do + assert_parsed_snapshot(<<~HTML) + <% loop do %> + <% break if condition %> +
Loop content
+ <% end %> + HTML + end end end diff --git a/test/analyze/unless_test.rb b/test/analyze/unless_test.rb index 4a53eff97..8bc0628fb 100644 --- a/test/analyze/unless_test.rb +++ b/test/analyze/unless_test.rb @@ -65,5 +65,56 @@ class UnlessTest < Minitest::Spec <% end %> HTML end + + test "guard clause with unless modifier should not be parsed as ERBUnlessNode" do + assert_parsed_snapshot(<<~HTML) + <% items.each do |item| %> + <% next unless item.visible? %> +
<%= item.name %>
+ <% end %> + HTML + end + + test "guard clause with return unless modifier" do + assert_parsed_snapshot(<<~HTML) + <% def some_method %> + <% return unless condition %> +
This will render
+ <% end %> + HTML + end + + test "guard clause with break unless modifier" do + assert_parsed_snapshot(<<~HTML) + <% loop do %> + <% break unless continue? %> +
Loop content
+ <% end %> + HTML + end + + test "multiple unless guard clauses" do + assert_parsed_snapshot(<<~HTML) + <% items.each do |item| %> + <% next unless item %> + <% next unless item.active? %> + <% next unless item.published? %> +
<%= item.title %>
+ <% end %> + HTML + end + + test "distinguishes between block unless and modifier unless" do + assert_parsed_snapshot(<<~HTML) + <% items.each do |item| %> + <% next unless item.visible? %> + <% unless item.special? %> +
<%= item.name %>
+ <% else %> +
<%= item.name %>
+ <% end %> + <% end %> + HTML + end end end diff --git a/test/snapshots/analyze/if_test/test_0010_guard_clause_with_if_modifier_should_not_be_parsed_as_ERBIfNode_84c50d0087a29c69bf5125ce6ec79f86.txt b/test/snapshots/analyze/if_test/test_0010_guard_clause_with_if_modifier_should_not_be_parsed_as_ERBIfNode_84c50d0087a29c69bf5125ce6ec79f86.txt new file mode 100644 index 000000000..a2628958d --- /dev/null +++ b/test/snapshots/analyze/if_test/test_0010_guard_clause_with_if_modifier_should_not_be_parsed_as_ERBIfNode_84c50d0087a29c69bf5125ce6ec79f86.txt @@ -0,0 +1,53 @@ +@ DocumentNode (location: (1:0)-(5:0)) +└── children: (2 items) + ├── @ ERBBlockNode (location: (1:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " [1,2].each do |value| " (location: (1:2)-(1:25)) + │ ├── tag_closing: "%>" (location: (1:25)-(1:27)) + │ ├── body: (5 items) + │ │ ├── @ HTMLTextNode (location: (1:27)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:21)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " next if false " (location: (2:4)-(2:19)) + │ │ │ ├── tag_closing: "%>" (location: (2:19)-(2:21)) + │ │ │ ├── parsed: true + │ │ │ └── valid: false + │ │ │ + │ │ ├── @ HTMLTextNode (location: (2:21)-(3:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (3:2)-(3:13)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (3:2)-(3:7)) + │ │ │ │ ├── tag_opening: "<" (location: (3:2)-(3:3)) + │ │ │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ │ │ ├── tag_closing: ">" (location: (3:6)-(3:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ │ ├── body: [] + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (3:7)-(3:13)) + │ │ │ │ ├── tag_opening: "" (location: (3:12)-(3:13)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (3:13)-(4:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (4:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (4:0)-(4:2)) + │ ├── content: " end " (location: (4:2)-(4:7)) + │ └── tag_closing: "%>" (location: (4:7)-(4:9)) + │ + │ + └── @ HTMLTextNode (location: (4:9)-(5:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/if_test/test_0011_guard_clause_with_return_if_modifier_6a92e7d29b0b8ff99771a96e90f4ac10.txt b/test/snapshots/analyze/if_test/test_0011_guard_clause_with_return_if_modifier_6a92e7d29b0b8ff99771a96e90f4ac10.txt new file mode 100644 index 000000000..fe0f987c7 --- /dev/null +++ b/test/snapshots/analyze/if_test/test_0011_guard_clause_with_return_if_modifier_6a92e7d29b0b8ff99771a96e90f4ac10.txt @@ -0,0 +1,58 @@ +@ DocumentNode (location: (1:0)-(5:0)) +└── children: (8 items) + ├── @ ERBContentNode (location: (1:0)-(1:21)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " def some_method " (location: (1:2)-(1:19)) + │ ├── tag_closing: "%>" (location: (1:19)-(1:21)) + │ ├── parsed: true + │ └── valid: false + │ + ├── @ HTMLTextNode (location: (1:21)-(2:2)) + │ └── content: "\n " + │ + ├── @ ERBContentNode (location: (2:2)-(2:22)) + │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ ├── content: " return if true " (location: (2:4)-(2:20)) + │ ├── tag_closing: "%>" (location: (2:20)-(2:22)) + │ ├── parsed: true + │ └── valid: true + │ + ├── @ HTMLTextNode (location: (2:22)-(3:2)) + │ └── content: "\n " + │ + ├── @ HTMLElementNode (location: (3:2)-(3:30)) + │ ├── open_tag: + │ │ └── @ HTMLOpenTagNode (location: (3:2)-(3:7)) + │ │ ├── tag_opening: "<" (location: (3:2)-(3:3)) + │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ ├── tag_closing: ">" (location: (3:6)-(3:7)) + │ │ ├── children: [] + │ │ └── is_void: false + │ │ + │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ ├── body: (1 item) + │ │ └── @ HTMLTextNode (location: (3:7)-(3:24)) + │ │ └── content: "This won't render" + │ │ + │ ├── close_tag: + │ │ └── @ HTMLCloseTagNode (location: (3:24)-(3:30)) + │ │ ├── tag_opening: "" (location: (3:29)-(3:30)) + │ │ + │ ├── is_void: false + │ └── source: "HTML" + │ + ├── @ HTMLTextNode (location: (3:30)-(4:0)) + │ └── content: "\n" + │ + ├── @ ERBContentNode (location: (4:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (4:0)-(4:2)) + │ ├── content: " end " (location: (4:2)-(4:7)) + │ ├── tag_closing: "%>" (location: (4:7)-(4:9)) + │ ├── parsed: true + │ └── valid: false + │ + └── @ HTMLTextNode (location: (4:9)-(5:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/if_test/test_0012_guard_clause_with_break_if_modifier_41f095a3d010c4b7e9a38aa708b9054d.txt b/test/snapshots/analyze/if_test/test_0012_guard_clause_with_break_if_modifier_41f095a3d010c4b7e9a38aa708b9054d.txt new file mode 100644 index 000000000..02b208567 --- /dev/null +++ b/test/snapshots/analyze/if_test/test_0012_guard_clause_with_break_if_modifier_41f095a3d010c4b7e9a38aa708b9054d.txt @@ -0,0 +1,56 @@ +@ DocumentNode (location: (1:0)-(5:0)) +└── children: (2 items) + ├── @ ERBBlockNode (location: (1:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " loop do " (location: (1:2)-(1:11)) + │ ├── tag_closing: "%>" (location: (1:11)-(1:13)) + │ ├── body: (5 items) + │ │ ├── @ HTMLTextNode (location: (1:13)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:26)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " break if condition " (location: (2:4)-(2:24)) + │ │ │ ├── tag_closing: "%>" (location: (2:24)-(2:26)) + │ │ │ ├── parsed: true + │ │ │ └── valid: false + │ │ │ + │ │ ├── @ HTMLTextNode (location: (2:26)-(3:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (3:2)-(3:25)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (3:2)-(3:7)) + │ │ │ │ ├── tag_opening: "<" (location: (3:2)-(3:3)) + │ │ │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ │ │ ├── tag_closing: ">" (location: (3:6)-(3:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ │ ├── body: (1 item) + │ │ │ │ └── @ HTMLTextNode (location: (3:7)-(3:19)) + │ │ │ │ └── content: "Loop content" + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (3:19)-(3:25)) + │ │ │ │ ├── tag_opening: "" (location: (3:24)-(3:25)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (3:25)-(4:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (4:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (4:0)-(4:2)) + │ ├── content: " end " (location: (4:2)-(4:7)) + │ └── tag_closing: "%>" (location: (4:7)-(4:9)) + │ + │ + └── @ HTMLTextNode (location: (4:9)-(5:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/unless_test/test_0007_guard_clause_with_unless_modifier_should_not_be_parsed_as_ERBUnlessNode_647968bffc9de35b805b872472b322b7.txt b/test/snapshots/analyze/unless_test/test_0007_guard_clause_with_unless_modifier_should_not_be_parsed_as_ERBUnlessNode_647968bffc9de35b805b872472b322b7.txt new file mode 100644 index 000000000..2d9b82db4 --- /dev/null +++ b/test/snapshots/analyze/unless_test/test_0007_guard_clause_with_unless_modifier_should_not_be_parsed_as_ERBUnlessNode_647968bffc9de35b805b872472b322b7.txt @@ -0,0 +1,60 @@ +@ DocumentNode (location: (1:0)-(5:0)) +└── children: (2 items) + ├── @ ERBBlockNode (location: (1:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " items.each do |item| " (location: (1:2)-(1:24)) + │ ├── tag_closing: "%>" (location: (1:24)-(1:26)) + │ ├── body: (5 items) + │ │ ├── @ HTMLTextNode (location: (1:26)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:33)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " next unless item.visible? " (location: (2:4)-(2:31)) + │ │ │ ├── tag_closing: "%>" (location: (2:31)-(2:33)) + │ │ │ ├── parsed: true + │ │ │ └── valid: false + │ │ │ + │ │ ├── @ HTMLTextNode (location: (2:33)-(3:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (3:2)-(3:29)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (3:2)-(3:7)) + │ │ │ │ ├── tag_opening: "<" (location: (3:2)-(3:3)) + │ │ │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ │ │ ├── tag_closing: ">" (location: (3:6)-(3:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ │ ├── body: (1 item) + │ │ │ │ └── @ ERBContentNode (location: (3:7)-(3:23)) + │ │ │ │ ├── tag_opening: "<%=" (location: (3:7)-(3:10)) + │ │ │ │ ├── content: " item.name " (location: (3:10)-(3:21)) + │ │ │ │ ├── tag_closing: "%>" (location: (3:21)-(3:23)) + │ │ │ │ ├── parsed: true + │ │ │ │ └── valid: true + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (3:23)-(3:29)) + │ │ │ │ ├── tag_opening: "" (location: (3:28)-(3:29)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (3:29)-(4:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (4:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (4:0)-(4:2)) + │ ├── content: " end " (location: (4:2)-(4:7)) + │ └── tag_closing: "%>" (location: (4:7)-(4:9)) + │ + │ + └── @ HTMLTextNode (location: (4:9)-(5:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/unless_test/test_0008_guard_clause_with_return_unless_modifier_650bfc3134fa92038c335f96f9047860.txt b/test/snapshots/analyze/unless_test/test_0008_guard_clause_with_return_unless_modifier_650bfc3134fa92038c335f96f9047860.txt new file mode 100644 index 000000000..bc0fd0e21 --- /dev/null +++ b/test/snapshots/analyze/unless_test/test_0008_guard_clause_with_return_unless_modifier_650bfc3134fa92038c335f96f9047860.txt @@ -0,0 +1,58 @@ +@ DocumentNode (location: (1:0)-(5:0)) +└── children: (8 items) + ├── @ ERBContentNode (location: (1:0)-(1:21)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " def some_method " (location: (1:2)-(1:19)) + │ ├── tag_closing: "%>" (location: (1:19)-(1:21)) + │ ├── parsed: true + │ └── valid: false + │ + ├── @ HTMLTextNode (location: (1:21)-(2:2)) + │ └── content: "\n " + │ + ├── @ ERBContentNode (location: (2:2)-(2:31)) + │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ ├── content: " return unless condition " (location: (2:4)-(2:29)) + │ ├── tag_closing: "%>" (location: (2:29)-(2:31)) + │ ├── parsed: true + │ └── valid: true + │ + ├── @ HTMLTextNode (location: (2:31)-(3:2)) + │ └── content: "\n " + │ + ├── @ HTMLElementNode (location: (3:2)-(3:29)) + │ ├── open_tag: + │ │ └── @ HTMLOpenTagNode (location: (3:2)-(3:7)) + │ │ ├── tag_opening: "<" (location: (3:2)-(3:3)) + │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ ├── tag_closing: ">" (location: (3:6)-(3:7)) + │ │ ├── children: [] + │ │ └── is_void: false + │ │ + │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ ├── body: (1 item) + │ │ └── @ HTMLTextNode (location: (3:7)-(3:23)) + │ │ └── content: "This will render" + │ │ + │ ├── close_tag: + │ │ └── @ HTMLCloseTagNode (location: (3:23)-(3:29)) + │ │ ├── tag_opening: "" (location: (3:28)-(3:29)) + │ │ + │ ├── is_void: false + │ └── source: "HTML" + │ + ├── @ HTMLTextNode (location: (3:29)-(4:0)) + │ └── content: "\n" + │ + ├── @ ERBContentNode (location: (4:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (4:0)-(4:2)) + │ ├── content: " end " (location: (4:2)-(4:7)) + │ ├── tag_closing: "%>" (location: (4:7)-(4:9)) + │ ├── parsed: true + │ └── valid: false + │ + └── @ HTMLTextNode (location: (4:9)-(5:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/unless_test/test_0009_guard_clause_with_break_unless_modifier_5ae9786a5b6893828c737287cffd216f.txt b/test/snapshots/analyze/unless_test/test_0009_guard_clause_with_break_unless_modifier_5ae9786a5b6893828c737287cffd216f.txt new file mode 100644 index 000000000..844e63c5a --- /dev/null +++ b/test/snapshots/analyze/unless_test/test_0009_guard_clause_with_break_unless_modifier_5ae9786a5b6893828c737287cffd216f.txt @@ -0,0 +1,56 @@ +@ DocumentNode (location: (1:0)-(5:0)) +└── children: (2 items) + ├── @ ERBBlockNode (location: (1:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " loop do " (location: (1:2)-(1:11)) + │ ├── tag_closing: "%>" (location: (1:11)-(1:13)) + │ ├── body: (5 items) + │ │ ├── @ HTMLTextNode (location: (1:13)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:30)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " break unless continue? " (location: (2:4)-(2:28)) + │ │ │ ├── tag_closing: "%>" (location: (2:28)-(2:30)) + │ │ │ ├── parsed: true + │ │ │ └── valid: false + │ │ │ + │ │ ├── @ HTMLTextNode (location: (2:30)-(3:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (3:2)-(3:25)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (3:2)-(3:7)) + │ │ │ │ ├── tag_opening: "<" (location: (3:2)-(3:3)) + │ │ │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ │ │ ├── tag_closing: ">" (location: (3:6)-(3:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (3:3)-(3:6)) + │ │ │ ├── body: (1 item) + │ │ │ │ └── @ HTMLTextNode (location: (3:7)-(3:19)) + │ │ │ │ └── content: "Loop content" + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (3:19)-(3:25)) + │ │ │ │ ├── tag_opening: "" (location: (3:24)-(3:25)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (3:25)-(4:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (4:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (4:0)-(4:2)) + │ ├── content: " end " (location: (4:2)-(4:7)) + │ └── tag_closing: "%>" (location: (4:7)-(4:9)) + │ + │ + └── @ HTMLTextNode (location: (4:9)-(5:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/unless_test/test_0010_multiple_unless_guard_clauses_80edd1ae63fb2cd18f33418d1ef308c1.txt b/test/snapshots/analyze/unless_test/test_0010_multiple_unless_guard_clauses_80edd1ae63fb2cd18f33418d1ef308c1.txt new file mode 100644 index 000000000..5819fd67d --- /dev/null +++ b/test/snapshots/analyze/unless_test/test_0010_multiple_unless_guard_clauses_80edd1ae63fb2cd18f33418d1ef308c1.txt @@ -0,0 +1,80 @@ +@ DocumentNode (location: (1:0)-(7:0)) +└── children: (2 items) + ├── @ ERBBlockNode (location: (1:0)-(6:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " items.each do |item| " (location: (1:2)-(1:24)) + │ ├── tag_closing: "%>" (location: (1:24)-(1:26)) + │ ├── body: (9 items) + │ │ ├── @ HTMLTextNode (location: (1:26)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:24)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " next unless item " (location: (2:4)-(2:22)) + │ │ │ ├── tag_closing: "%>" (location: (2:22)-(2:24)) + │ │ │ ├── parsed: true + │ │ │ └── valid: false + │ │ │ + │ │ ├── @ HTMLTextNode (location: (2:24)-(3:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (3:2)-(3:32)) + │ │ │ ├── tag_opening: "<%" (location: (3:2)-(3:4)) + │ │ │ ├── content: " next unless item.active? " (location: (3:4)-(3:30)) + │ │ │ ├── tag_closing: "%>" (location: (3:30)-(3:32)) + │ │ │ ├── parsed: true + │ │ │ └── valid: false + │ │ │ + │ │ ├── @ HTMLTextNode (location: (3:32)-(4:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (4:2)-(4:35)) + │ │ │ ├── tag_opening: "<%" (location: (4:2)-(4:4)) + │ │ │ ├── content: " next unless item.published? " (location: (4:4)-(4:33)) + │ │ │ ├── tag_closing: "%>" (location: (4:33)-(4:35)) + │ │ │ ├── parsed: true + │ │ │ └── valid: false + │ │ │ + │ │ ├── @ HTMLTextNode (location: (4:35)-(5:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (5:2)-(5:30)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ HTMLOpenTagNode (location: (5:2)-(5:7)) + │ │ │ │ ├── tag_opening: "<" (location: (5:2)-(5:3)) + │ │ │ │ ├── tag_name: "div" (location: (5:3)-(5:6)) + │ │ │ │ ├── tag_closing: ">" (location: (5:6)-(5:7)) + │ │ │ │ ├── children: [] + │ │ │ │ └── is_void: false + │ │ │ │ + │ │ │ ├── tag_name: "div" (location: (5:3)-(5:6)) + │ │ │ ├── body: (1 item) + │ │ │ │ └── @ ERBContentNode (location: (5:7)-(5:24)) + │ │ │ │ ├── tag_opening: "<%=" (location: (5:7)-(5:10)) + │ │ │ │ ├── content: " item.title " (location: (5:10)-(5:22)) + │ │ │ │ ├── tag_closing: "%>" (location: (5:22)-(5:24)) + │ │ │ │ ├── parsed: true + │ │ │ │ └── valid: true + │ │ │ │ + │ │ │ ├── close_tag: + │ │ │ │ └── @ HTMLCloseTagNode (location: (5:24)-(5:30)) + │ │ │ │ ├── tag_opening: "" (location: (5:29)-(5:30)) + │ │ │ │ + │ │ │ ├── is_void: false + │ │ │ └── source: "HTML" + │ │ │ + │ │ └── @ HTMLTextNode (location: (5:30)-(6:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (6:0)-(6:9)) + │ ├── tag_opening: "<%" (location: (6:0)-(6:2)) + │ ├── content: " end " (location: (6:2)-(6:7)) + │ └── tag_closing: "%>" (location: (6:7)-(6:9)) + │ + │ + └── @ HTMLTextNode (location: (6:9)-(7:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/unless_test/test_0011_distinguishes_between_block_unless_and_modifier_unless_4ca85acaceb3fb39b75797c6a07e7437.txt b/test/snapshots/analyze/unless_test/test_0011_distinguishes_between_block_unless_and_modifier_unless_4ca85acaceb3fb39b75797c6a07e7437.txt new file mode 100644 index 000000000..6b99a9218 --- /dev/null +++ b/test/snapshots/analyze/unless_test/test_0011_distinguishes_between_block_unless_and_modifier_unless_4ca85acaceb3fb39b75797c6a07e7437.txt @@ -0,0 +1,159 @@ +@ DocumentNode (location: (1:0)-(9:0)) +└── children: (2 items) + ├── @ ERBBlockNode (location: (1:0)-(8:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " items.each do |item| " (location: (1:2)-(1:24)) + │ ├── tag_closing: "%>" (location: (1:24)-(1:26)) + │ ├── body: (5 items) + │ │ ├── @ HTMLTextNode (location: (1:26)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:33)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " next unless item.visible? " (location: (2:4)-(2:31)) + │ │ │ ├── tag_closing: "%>" (location: (2:31)-(2:33)) + │ │ │ ├── parsed: true + │ │ │ └── valid: false + │ │ │ + │ │ ├── @ HTMLTextNode (location: (2:33)-(3:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBUnlessNode (location: (3:2)-(7:11)) + │ │ │ ├── tag_opening: "<%" (location: (3:2)-(3:4)) + │ │ │ ├── content: " unless item.special? " (location: (3:4)-(3:26)) + │ │ │ ├── tag_closing: "%>" (location: (3:26)-(3:28)) + │ │ │ ├── statements: (3 items) + │ │ │ │ ├── @ HTMLTextNode (location: (3:28)-(4:4)) + │ │ │ │ │ └── content: "\n " + │ │ │ │ │ + │ │ │ │ ├── @ HTMLElementNode (location: (4:4)-(4:46)) + │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (4:4)-(4:24)) + │ │ │ │ │ │ ├── tag_opening: "<" (location: (4:4)-(4:5)) + │ │ │ │ │ │ ├── tag_name: "div" (location: (4:5)-(4:8)) + │ │ │ │ │ │ ├── tag_closing: ">" (location: (4:23)-(4:24)) + │ │ │ │ │ │ ├── children: (1 item) + │ │ │ │ │ │ │ └── @ HTMLAttributeNode (location: (4:9)-(4:23)) + │ │ │ │ │ │ │ ├── name: + │ │ │ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (4:9)-(4:14)) + │ │ │ │ │ │ │ │ └── children: (1 item) + │ │ │ │ │ │ │ │ └── @ LiteralNode (location: (4:9)-(4:14)) + │ │ │ │ │ │ │ │ └── content: "class" + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── equals: "=" (location: (4:14)-(4:15)) + │ │ │ │ │ │ │ └── value: + │ │ │ │ │ │ │ └── @ HTMLAttributeValueNode (location: (4:15)-(4:23)) + │ │ │ │ │ │ │ ├── open_quote: """ (location: (4:15)-(4:16)) + │ │ │ │ │ │ │ ├── children: (1 item) + │ │ │ │ │ │ │ │ └── @ LiteralNode (location: (4:16)-(4:22)) + │ │ │ │ │ │ │ │ └── content: "normal" + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── close_quote: """ (location: (4:22)-(4:23)) + │ │ │ │ │ │ │ └── quoted: true + │ │ │ │ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ + │ │ │ │ │ ├── tag_name: "div" (location: (4:5)-(4:8)) + │ │ │ │ │ ├── body: (1 item) + │ │ │ │ │ │ └── @ ERBContentNode (location: (4:24)-(4:40)) + │ │ │ │ │ │ ├── tag_opening: "<%=" (location: (4:24)-(4:27)) + │ │ │ │ │ │ ├── content: " item.name " (location: (4:27)-(4:38)) + │ │ │ │ │ │ ├── tag_closing: "%>" (location: (4:38)-(4:40)) + │ │ │ │ │ │ ├── parsed: true + │ │ │ │ │ │ └── valid: true + │ │ │ │ │ │ + │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (4:40)-(4:46)) + │ │ │ │ │ │ ├── tag_opening: "" (location: (4:45)-(4:46)) + │ │ │ │ │ │ + │ │ │ │ │ ├── is_void: false + │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ + │ │ │ │ └── @ HTMLTextNode (location: (4:46)-(5:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ ├── else_clause: + │ │ │ │ └── @ ERBElseNode (location: (5:2)-(7:2)) + │ │ │ │ ├── tag_opening: "<%" (location: (5:2)-(5:4)) + │ │ │ │ ├── content: " else " (location: (5:4)-(5:10)) + │ │ │ │ ├── tag_closing: "%>" (location: (5:10)-(5:12)) + │ │ │ │ └── statements: (3 items) + │ │ │ │ ├── @ HTMLTextNode (location: (5:12)-(6:4)) + │ │ │ │ │ └── content: "\n " + │ │ │ │ │ + │ │ │ │ ├── @ HTMLElementNode (location: (6:4)-(6:47)) + │ │ │ │ │ ├── open_tag: + │ │ │ │ │ │ └── @ HTMLOpenTagNode (location: (6:4)-(6:25)) + │ │ │ │ │ │ ├── tag_opening: "<" (location: (6:4)-(6:5)) + │ │ │ │ │ │ ├── tag_name: "div" (location: (6:5)-(6:8)) + │ │ │ │ │ │ ├── tag_closing: ">" (location: (6:24)-(6:25)) + │ │ │ │ │ │ ├── children: (1 item) + │ │ │ │ │ │ │ └── @ HTMLAttributeNode (location: (6:9)-(6:24)) + │ │ │ │ │ │ │ ├── name: + │ │ │ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (6:9)-(6:14)) + │ │ │ │ │ │ │ │ └── children: (1 item) + │ │ │ │ │ │ │ │ └── @ LiteralNode (location: (6:9)-(6:14)) + │ │ │ │ │ │ │ │ └── content: "class" + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── equals: "=" (location: (6:14)-(6:15)) + │ │ │ │ │ │ │ └── value: + │ │ │ │ │ │ │ └── @ HTMLAttributeValueNode (location: (6:15)-(6:24)) + │ │ │ │ │ │ │ ├── open_quote: """ (location: (6:15)-(6:16)) + │ │ │ │ │ │ │ ├── children: (1 item) + │ │ │ │ │ │ │ │ └── @ LiteralNode (location: (6:16)-(6:23)) + │ │ │ │ │ │ │ │ └── content: "special" + │ │ │ │ │ │ │ │ + │ │ │ │ │ │ │ ├── close_quote: """ (location: (6:23)-(6:24)) + │ │ │ │ │ │ │ └── quoted: true + │ │ │ │ │ │ │ + │ │ │ │ │ │ │ + │ │ │ │ │ │ └── is_void: false + │ │ │ │ │ │ + │ │ │ │ │ ├── tag_name: "div" (location: (6:5)-(6:8)) + │ │ │ │ │ ├── body: (1 item) + │ │ │ │ │ │ └── @ ERBContentNode (location: (6:25)-(6:41)) + │ │ │ │ │ │ ├── tag_opening: "<%=" (location: (6:25)-(6:28)) + │ │ │ │ │ │ ├── content: " item.name " (location: (6:28)-(6:39)) + │ │ │ │ │ │ ├── tag_closing: "%>" (location: (6:39)-(6:41)) + │ │ │ │ │ │ ├── parsed: true + │ │ │ │ │ │ └── valid: true + │ │ │ │ │ │ + │ │ │ │ │ ├── close_tag: + │ │ │ │ │ │ └── @ HTMLCloseTagNode (location: (6:41)-(6:47)) + │ │ │ │ │ │ ├── tag_opening: "" (location: (6:46)-(6:47)) + │ │ │ │ │ │ + │ │ │ │ │ ├── is_void: false + │ │ │ │ │ └── source: "HTML" + │ │ │ │ │ + │ │ │ │ └── @ HTMLTextNode (location: (6:47)-(7:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ │ + │ │ │ └── end_node: + │ │ │ └── @ ERBEndNode (location: (7:2)-(7:11)) + │ │ │ ├── tag_opening: "<%" (location: (7:2)-(7:4)) + │ │ │ ├── content: " end " (location: (7:4)-(7:9)) + │ │ │ └── tag_closing: "%>" (location: (7:9)-(7:11)) + │ │ │ + │ │ │ + │ │ └── @ HTMLTextNode (location: (7:11)-(8:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (8:0)-(8:9)) + │ ├── tag_opening: "<%" (location: (8:0)-(8:2)) + │ ├── content: " end " (location: (8:2)-(8:7)) + │ └── tag_closing: "%>" (location: (8:7)-(8:9)) + │ + │ + └── @ HTMLTextNode (location: (8:9)-(9:0)) + └── content: "\n" \ No newline at end of file From 70321d46fb056a01e273eb16f1ee04b6e8a70481 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 18:11:41 +0100 Subject: [PATCH 22/34] Bump vite from 7.0.7 to 7.1.5 in the npm_and_yarn group across 1 directory (#519) Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 7.0.7 to 7.1.5 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- playground/package.json | 2 +- yarn.lock | 40 +++++++++++++--------------------------- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/playground/package.json b/playground/package.json index 999f6ebd1..0bd16a63a 100644 --- a/playground/package.json +++ b/playground/package.json @@ -28,7 +28,7 @@ "lz-string": "^1.5.0", "monaco-editor": "^0.52.2", "prismjs": "^1.30.0", - "vite": "^7.0.7" + "vite": "^7.1.5" }, "devDependencies": { "@types/express": "^4.17.21", diff --git a/yarn.lock b/yarn.lock index 044d9969d..8bac1f8f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4591,7 +4591,7 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -fdir@^6.2.0, fdir@^6.4.4, fdir@^6.4.6, fdir@^6.5.0: +fdir@^6.2.0, fdir@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== @@ -8666,7 +8666,7 @@ rollup-pluginutils@^2.8.2: dependencies: estree-walker "^0.6.1" -rollup@^4.20.0, rollup@^4.34.8, rollup@^4.40.0, rollup@^4.43.0, rollup@^4.47.1: +rollup@^4.20.0, rollup@^4.34.8, rollup@^4.43.0, rollup@^4.47.1: version "4.52.0" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.52.0.tgz#5a906bf98f7c7a2c08d2b18fbfa52955552423d7" integrity sha512-+IuescNkTJQgX7AkIDtITipZdIGcWF0pnVvZTWStiazUmcGA2ag8dfg0urest2XlXUi9kuhfQ+qmdc5Stc3z7g== @@ -9632,13 +9632,13 @@ tinyexec@^1.0.1: resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1" integrity sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw== -tinyglobby@^0.2.11, tinyglobby@^0.2.14: - version "0.2.14" - resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" - integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== +tinyglobby@^0.2.11, tinyglobby@^0.2.14, tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== dependencies: - fdir "^6.4.4" - picomatch "^4.0.2" + fdir "^6.5.0" + picomatch "^4.0.3" tinypool@^0.8.3: version "0.8.4" @@ -10169,31 +10169,17 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.1.2: - version "7.1.3" - resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.3.tgz#8d70cb02fd6346b4bf1329a6760800538ef0faea" - integrity sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw== +"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.1.2, vite@^7.1.5: + version "7.1.5" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.5.tgz#4dbcb48c6313116689be540466fc80faa377be38" + integrity sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ== dependencies: esbuild "^0.25.0" fdir "^6.5.0" picomatch "^4.0.3" postcss "^8.5.6" rollup "^4.43.0" - tinyglobby "^0.2.14" - optionalDependencies: - fsevents "~2.3.3" - -vite@^7.0.7: - version "7.0.7" - resolved "https://registry.yarnpkg.com/vite/-/vite-7.0.7.tgz#d883a0297d24139237676f4227ac2b1e72f9677b" - integrity sha512-hc6LujN/EkJHmxeiDJMs0qBontZ1cdBvvoCbWhVjzUFTU329VRyOC46gHNSA8NcOC5yzCeXpwI40tieI3DEZqg== - dependencies: - esbuild "^0.25.0" - fdir "^6.4.6" - picomatch "^4.0.3" - postcss "^8.5.6" - rollup "^4.40.0" - tinyglobby "^0.2.14" + tinyglobby "^0.2.15" optionalDependencies: fsevents "~2.3.3" From a825db82525b428a2ebae1613c0b69d3b6c3c698 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 19:44:52 +0200 Subject: [PATCH 23/34] Bump vite from 7.1.5 to 7.1.6 in the npm_and_yarn group across 1 directory (#520) Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 7.1.5 to 7.1.6 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- playground/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/playground/package.json b/playground/package.json index 0bd16a63a..54630eadb 100644 --- a/playground/package.json +++ b/playground/package.json @@ -28,7 +28,7 @@ "lz-string": "^1.5.0", "monaco-editor": "^0.52.2", "prismjs": "^1.30.0", - "vite": "^7.1.5" + "vite": "^7.1.6" }, "devDependencies": { "@types/express": "^4.17.21", diff --git a/yarn.lock b/yarn.lock index 8bac1f8f5..af3660afb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10169,10 +10169,10 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.1.2, vite@^7.1.5: - version "7.1.5" - resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.5.tgz#4dbcb48c6313116689be540466fc80faa377be38" - integrity sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ== +"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.1.2, vite@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.6.tgz#336806d29983135677f498a05efb0fd46c5eef2d" + integrity sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ== dependencies: esbuild "^0.25.0" fdir "^6.5.0" From 04d1ffc6fa315f108a8e85df40ec0bcc3491866e Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Mon, 22 Sep 2025 18:50:35 +0100 Subject: [PATCH 24/34] Linter: Allow empty data attributes with no value (#518) This pull request updates the `html-no-empty-attributes` linter rule to allow for empty data attributes without an equal sign and attribute value. This **is not** allowed: ```html
``` This **is** now allowed with this pull request: ```html
``` Resolves https://github.com/marcoroth/herb/issues/483 --- .../src/rules/html-no-empty-attributes.ts | 40 +++++++--- .../test/__snapshots__/cli.test.ts.snap | 6 +- .../rules/html-no-empty-attributes.test.ts | 75 +++++++++++++++++-- 3 files changed, 100 insertions(+), 21 deletions(-) diff --git a/javascript/packages/linter/src/rules/html-no-empty-attributes.ts b/javascript/packages/linter/src/rules/html-no-empty-attributes.ts index 1d03df1f0..b0cc8eec6 100644 --- a/javascript/packages/linter/src/rules/html-no-empty-attributes.ts +++ b/javascript/packages/linter/src/rules/html-no-empty-attributes.ts @@ -1,8 +1,9 @@ import { ParserRule } from "../types.js" import { AttributeVisitorMixin, StaticAttributeStaticValueParams, DynamicAttributeStaticValueParams } from "./rule-utils.js" +import { IdentityPrinter } from "@herb-tools/printer" import type { LintOffense, LintContext } from "../types.js" -import type { ParseResult } from "@herb-tools/core" +import type { ParseResult, HTMLAttributeNode } from "@herb-tools/core" // Attributes that must not have empty values const RESTRICTED_ATTRIBUTES = new Set([ @@ -37,26 +38,41 @@ function isRestrictedAttribute(attributeName: string): boolean { return false } +function isDataAttribute(attributeName: string): boolean { + return attributeName.startsWith('data-') +} + class NoEmptyAttributesVisitor extends AttributeVisitorMixin { protected checkStaticAttributeStaticValue({ attributeName, attributeValue, attributeNode }: StaticAttributeStaticValueParams): void { - if (!isRestrictedAttribute(attributeName)) return - if (attributeValue.trim() !== "") return - - this.addOffense( - `Attribute \`${attributeName}\` must not be empty. Either provide a meaningful value or remove the attribute entirely.`, - attributeNode.name!.location, - "warning" - ) + this.checkEmptyAttribute(attributeName, attributeValue, attributeNode) } protected checkDynamicAttributeStaticValue({ combinedName, attributeValue, attributeNode }: DynamicAttributeStaticValueParams): void { const name = (combinedName || "").toLowerCase() - if (!isRestrictedAttribute(name)) return + this.checkEmptyAttribute(name, attributeValue, attributeNode) + } + + private checkEmptyAttribute(attributeName: string, attributeValue: string, attributeNode: HTMLAttributeNode): void { + if (!isRestrictedAttribute(attributeName)) return if (attributeValue.trim() !== "") return + const hasExplicitValue = attributeNode.value !== null + + if (isDataAttribute(attributeName)) { + if (hasExplicitValue) { + this.addOffense( + `Data attribute \`${attributeName}\` should not have an empty value. Either provide a meaningful value or use \`${attributeName}\` instead of \`${IdentityPrinter.print(attributeNode)}\`.`, + attributeNode.location, + "warning" + ) + } + + return + } + this.addOffense( - `Attribute \`${combinedName}\` must not be empty. Either provide a meaningful value or remove the attribute entirely.`, - attributeNode.name!.location, + `Attribute \`${attributeName}\` must not be empty. Either provide a meaningful value or remove the attribute entirely.`, + attributeNode.location, "warning" ) } diff --git a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap index 96fc07508..8a1a0fc38 100644 --- a/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap +++ b/javascript/packages/linter/test/__snapshots__/cli.test.ts.snap @@ -193,7 +193,7 @@ test/fixtures/multiple-rule-offenses.html.erb:3:14 1 │ 2 │ → 3 │
- │ ~~~~~ + │ ~~~~~~~~ 4 │ 5 │ Link 1 @@ -207,7 +207,7 @@ test/fixtures/multiple-rule-offenses.html.erb:5:5 3 │
4 │ → 5 │ Link 1 - │ ~~~~~ + │ ~~~~~~~~ 6 │
7 │ @@ -221,7 +221,7 @@ test/fixtures/multiple-rule-offenses.html.erb:5:14 3 │
4 │ → 5 │ Link 1 - │ ~~~~~ + │ ~~~~~~~~ 6 │
7 │ diff --git a/javascript/packages/linter/test/rules/html-no-empty-attributes.test.ts b/javascript/packages/linter/test/rules/html-no-empty-attributes.test.ts index bc875ff59..6a71543b4 100644 --- a/javascript/packages/linter/test/rules/html-no-empty-attributes.test.ts +++ b/javascript/packages/linter/test/rules/html-no-empty-attributes.test.ts @@ -132,9 +132,9 @@ describe("html-no-empty-attributes", () => { expect(lintResult.errors).toBe(0) expect(lintResult.warnings).toBe(2) - expect(lintResult.offenses[0].message).toBe('Attribute `data-value` must not be empty. Either provide a meaningful value or remove the attribute entirely.') + expect(lintResult.offenses[0].message).toBe('Data attribute `data-value` should not have an empty value. Either provide a meaningful value or use `data-value` instead of `data-value=""`.') expect(lintResult.offenses[0].severity).toBe("warning") - expect(lintResult.offenses[1].message).toBe('Attribute `data-config` must not be empty. Either provide a meaningful value or remove the attribute entirely.') + expect(lintResult.offenses[1].message).toBe('Data attribute `data-config` should not have an empty value. Either provide a meaningful value or use `data-config` instead of `data-config=""`.') expect(lintResult.offenses[1].severity).toBe("warning") }) @@ -179,7 +179,7 @@ describe("html-no-empty-attributes", () => { expect(lintResult.offenses[0].severity).toBe("warning") expect(lintResult.offenses[1].message).toBe('Attribute `class` must not be empty. Either provide a meaningful value or remove the attribute entirely.') expect(lintResult.offenses[1].severity).toBe("warning") - expect(lintResult.offenses[2].message).toBe('Attribute `data-test` must not be empty. Either provide a meaningful value or remove the attribute entirely.') + expect(lintResult.offenses[2].message).toBe('Data attribute `data-test` should not have an empty value. Either provide a meaningful value or use `data-test` instead of `data-test=""`.') expect(lintResult.offenses[2].severity).toBe("warning") }) @@ -226,7 +226,7 @@ describe("html-no-empty-attributes", () => { expect(lintResult.errors).toBe(0) expect(lintResult.warnings).toBe(1) - expect(lintResult.offenses[0].message).toBe('Attribute `data-<%= key %>` must not be empty. Either provide a meaningful value or remove the attribute entirely.') + expect(lintResult.offenses[0].message).toBe('Data attribute `data-<%= key %>` should not have an empty value. Either provide a meaningful value or use `data-<%= key %>` instead of `data-<%= key %>=""`.') expect(lintResult.offenses[0].severity).toBe("warning") }) @@ -238,7 +238,7 @@ describe("html-no-empty-attributes", () => { expect(lintResult.errors).toBe(0) expect(lintResult.warnings).toBe(1) - expect(lintResult.offenses[0].message).toBe('Attribute `data-<%= key %>-id` must not be empty. Either provide a meaningful value or remove the attribute entirely.') + expect(lintResult.offenses[0].message).toBe('Data attribute `data-<%= key %>-id` should not have an empty value. Either provide a meaningful value or use `data-<%= key %>-id` instead of `data-<%= key %>-id=""`.') expect(lintResult.offenses[0].severity).toBe("warning") }) @@ -250,7 +250,7 @@ describe("html-no-empty-attributes", () => { expect(lintResult.errors).toBe(0) expect(lintResult.warnings).toBe(1) - expect(lintResult.offenses[0].message).toBe('Attribute `data-<%= key %>` must not be empty. Either provide a meaningful value or remove the attribute entirely.') + expect(lintResult.offenses[0].message).toBe('Data attribute `data-<%= key %>` should not have an empty value. Either provide a meaningful value or use `data-<%= key %>` instead of `data-<%= key %>=" "`.') expect(lintResult.offenses[0].severity).toBe("warning") }) @@ -296,4 +296,67 @@ describe("html-no-empty-attributes", () => { expect(lintResult.errors).toBe(0) expect(lintResult.warnings).toBe(0) }) + + test("passes for data-* attributes without explicit values", () => { + const html = '
' + + const linter = new Linter(Herb, [HTMLNoEmptyAttributesRule]) + const lintResult = linter.lint(html) + + expect(lintResult.errors).toBe(0) + expect(lintResult.warnings).toBe(0) + expect(lintResult.offenses).toHaveLength(0) + }) + + test("fails for data-* attributes with explicit empty string values", () => { + const html = '
' + + const linter = new Linter(Herb, [HTMLNoEmptyAttributesRule]) + const lintResult = linter.lint(html) + + expect(lintResult.errors).toBe(0) + expect(lintResult.warnings).toBe(2) + + expect(lintResult.offenses[0].message).toBe('Data attribute `data-test` should not have an empty value. Either provide a meaningful value or use `data-test` instead of `data-test=""`.') + expect(lintResult.offenses[0].severity).toBe("warning") + expect(lintResult.offenses[1].message).toBe('Data attribute `data-value` should not have an empty value. Either provide a meaningful value or use `data-value` instead of `data-value=""`.') + expect(lintResult.offenses[1].severity).toBe("warning") + }) + + test("mixed data attributes: passes for implicit values, fails for explicit empty values", () => { + const html = '
' + + const linter = new Linter(Herb, [HTMLNoEmptyAttributesRule]) + const lintResult = linter.lint(html) + + expect(lintResult.errors).toBe(0) + expect(lintResult.warnings).toBe(1) + + expect(lintResult.offenses[0].message).toBe('Data attribute `data-config` should not have an empty value. Either provide a meaningful value or use `data-config` instead of `data-config=""`.') + expect(lintResult.offenses[0].severity).toBe("warning") + }) + + test("passes for data-turbo-permanent without value", () => { + const html = '
Content
' + + const linter = new Linter(Herb, [HTMLNoEmptyAttributesRule]) + const lintResult = linter.lint(html) + + expect(lintResult.errors).toBe(0) + expect(lintResult.warnings).toBe(0) + expect(lintResult.offenses).toHaveLength(0) + }) + + test("fails for data-turbo-permanent with explicit empty value", () => { + const html = '
Content
' + + const linter = new Linter(Herb, [HTMLNoEmptyAttributesRule]) + const lintResult = linter.lint(html) + + expect(lintResult.errors).toBe(0) + expect(lintResult.warnings).toBe(1) + + expect(lintResult.offenses[0].message).toBe('Data attribute `data-turbo-permanent` should not have an empty value. Either provide a meaningful value or use `data-turbo-permanent` instead of `data-turbo-permanent=""`.') + expect(lintResult.offenses[0].severity).toBe("warning") + }) }) From ca511a8fae3dfcfa2bfb1885409a26c79d6ad46f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 20:18:29 +0200 Subject: [PATCH 25/34] Bump vite from 7.1.6 to 7.1.7 in the npm_and_yarn group across 1 directory (#521) Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 7.1.6 to 7.1.7 Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- playground/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/playground/package.json b/playground/package.json index 54630eadb..8b98f58de 100644 --- a/playground/package.json +++ b/playground/package.json @@ -28,7 +28,7 @@ "lz-string": "^1.5.0", "monaco-editor": "^0.52.2", "prismjs": "^1.30.0", - "vite": "^7.1.6" + "vite": "^7.1.7" }, "devDependencies": { "@types/express": "^4.17.21", diff --git a/yarn.lock b/yarn.lock index af3660afb..523745528 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10169,10 +10169,10 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.1.2, vite@^7.1.6: - version "7.1.6" - resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.6.tgz#336806d29983135677f498a05efb0fd46c5eef2d" - integrity sha512-SRYIB8t/isTwNn8vMB3MR6E+EQZM/WG1aKmmIUCfDXfVvKfc20ZpamngWHKzAmmu9ppsgxsg4b2I7c90JZudIQ== +"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.1.2, vite@^7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.1.7.tgz#ed3f9f06e21d6574fe1ad425f6b0912d027ffc13" + integrity sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA== dependencies: esbuild "^0.25.0" fdir "^6.5.0" From 6fcbe3f4a6608ed9b547ec4d9905cbaa850d907b Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Mon, 22 Sep 2025 19:27:54 +0100 Subject: [PATCH 26/34] Formatter: Fix attribute spacing in content-preserving elements (#522) This pull request updates to formatter to fix an issue where HTML elements inside `
`, `