rhales 0.3.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/.github/renovate.json5 +52 -0
  3. data/.github/workflows/ci.yml +123 -0
  4. data/.github/workflows/claude-code-review.yml +69 -0
  5. data/.github/workflows/claude.yml +49 -0
  6. data/.github/workflows/code-smells.yml +146 -0
  7. data/.github/workflows/ruby-lint.yml +78 -0
  8. data/.github/workflows/yardoc.yml +126 -0
  9. data/.gitignore +55 -0
  10. data/.pr_agent.toml +63 -0
  11. data/.pre-commit-config.yaml +89 -0
  12. data/.prettierignore +8 -0
  13. data/.prettierrc +38 -0
  14. data/.reek.yml +98 -0
  15. data/.rubocop.yml +428 -0
  16. data/.serena/.gitignore +3 -0
  17. data/.yardopts +56 -0
  18. data/CHANGELOG.md +44 -0
  19. data/CLAUDE.md +1 -2
  20. data/Gemfile +29 -0
  21. data/Gemfile.lock +189 -0
  22. data/README.md +706 -589
  23. data/Rakefile +46 -0
  24. data/debug_context.rb +25 -0
  25. data/demo/rhales-roda-demo/.gitignore +7 -0
  26. data/demo/rhales-roda-demo/Gemfile +32 -0
  27. data/demo/rhales-roda-demo/Gemfile.lock +151 -0
  28. data/demo/rhales-roda-demo/MAIL.md +405 -0
  29. data/demo/rhales-roda-demo/README.md +376 -0
  30. data/demo/rhales-roda-demo/RODA-TEMPLATE-ENGINES.md +192 -0
  31. data/demo/rhales-roda-demo/Rakefile +49 -0
  32. data/demo/rhales-roda-demo/app.rb +325 -0
  33. data/demo/rhales-roda-demo/bin/rackup +26 -0
  34. data/demo/rhales-roda-demo/config.ru +13 -0
  35. data/demo/rhales-roda-demo/db/migrate/001_create_rodauth_tables.rb +266 -0
  36. data/demo/rhales-roda-demo/db/migrate/002_create_rodauth_password_tables.rb +79 -0
  37. data/demo/rhales-roda-demo/db/migrate/003_add_admin_account.rb +68 -0
  38. data/demo/rhales-roda-demo/templates/change_login.rue +31 -0
  39. data/demo/rhales-roda-demo/templates/change_password.rue +36 -0
  40. data/demo/rhales-roda-demo/templates/close_account.rue +31 -0
  41. data/demo/rhales-roda-demo/templates/create_account.rue +40 -0
  42. data/demo/rhales-roda-demo/templates/dashboard.rue +150 -0
  43. data/demo/rhales-roda-demo/templates/home.rue +78 -0
  44. data/demo/rhales-roda-demo/templates/layouts/main.rue +168 -0
  45. data/demo/rhales-roda-demo/templates/login.rue +65 -0
  46. data/demo/rhales-roda-demo/templates/logout.rue +25 -0
  47. data/demo/rhales-roda-demo/templates/reset_password.rue +26 -0
  48. data/demo/rhales-roda-demo/templates/verify_account.rue +27 -0
  49. data/demo/rhales-roda-demo/test_full_output.rb +27 -0
  50. data/demo/rhales-roda-demo/test_simple.rb +24 -0
  51. data/docs/.gitignore +9 -0
  52. data/docs/architecture/data-flow.md +499 -0
  53. data/examples/dashboard-with-charts.rue +271 -0
  54. data/examples/form-with-validation.rue +180 -0
  55. data/examples/simple-page.rue +61 -0
  56. data/examples/vue.rue +136 -0
  57. data/generate-json-schemas.ts +158 -0
  58. data/json_schemer_migration_summary.md +172 -0
  59. data/lib/rhales/adapters/base_auth.rb +2 -0
  60. data/lib/rhales/adapters/base_request.rb +2 -0
  61. data/lib/rhales/adapters/base_session.rb +2 -0
  62. data/lib/rhales/adapters.rb +7 -0
  63. data/lib/rhales/configuration.rb +161 -1
  64. data/lib/rhales/core/context.rb +354 -0
  65. data/lib/rhales/{rue_document.rb → core/rue_document.rb} +59 -43
  66. data/lib/rhales/{template_engine.rb → core/template_engine.rb} +80 -33
  67. data/lib/rhales/core/view.rb +529 -0
  68. data/lib/rhales/{view_composition.rb → core/view_composition.rb} +81 -9
  69. data/lib/rhales/core.rb +9 -0
  70. data/lib/rhales/errors/hydration_collision_error.rb +2 -0
  71. data/lib/rhales/errors.rb +2 -0
  72. data/lib/rhales/hydration/earliest_injection_detector.rb +153 -0
  73. data/lib/rhales/hydration/hydration_data_aggregator.rb +487 -0
  74. data/lib/rhales/hydration/hydration_endpoint.rb +215 -0
  75. data/lib/rhales/hydration/hydration_injector.rb +175 -0
  76. data/lib/rhales/{hydration_registry.rb → hydration/hydration_registry.rb} +2 -0
  77. data/lib/rhales/hydration/hydrator.rb +102 -0
  78. data/lib/rhales/hydration/link_based_injection_detector.rb +195 -0
  79. data/lib/rhales/hydration/mount_point_detector.rb +109 -0
  80. data/lib/rhales/hydration/safe_injection_validator.rb +103 -0
  81. data/lib/rhales/hydration.rb +13 -0
  82. data/lib/rhales/{refinements → integrations/refinements}/require_refinements.rb +7 -13
  83. data/lib/rhales/{tilt.rb → integrations/tilt.rb} +26 -18
  84. data/lib/rhales/integrations.rb +6 -0
  85. data/lib/rhales/middleware/json_responder.rb +191 -0
  86. data/lib/rhales/middleware/schema_validator.rb +300 -0
  87. data/lib/rhales/middleware.rb +6 -0
  88. data/lib/rhales/parsers/handlebars_parser.rb +2 -0
  89. data/lib/rhales/parsers/rue_format_parser.rb +55 -36
  90. data/lib/rhales/parsers.rb +9 -0
  91. data/lib/rhales/{csp.rb → security/csp.rb} +27 -3
  92. data/lib/rhales/utils/json_serializer.rb +114 -0
  93. data/lib/rhales/utils/logging_helpers.rb +75 -0
  94. data/lib/rhales/utils/schema_extractor.rb +132 -0
  95. data/lib/rhales/utils/schema_generator.rb +194 -0
  96. data/lib/rhales/utils.rb +40 -0
  97. data/lib/rhales/version.rb +5 -1
  98. data/lib/rhales.rb +47 -19
  99. data/lib/tasks/rhales_schema.rake +197 -0
  100. data/package.json +10 -0
  101. data/pnpm-lock.yaml +345 -0
  102. data/pnpm-workspace.yaml +2 -0
  103. data/proofs/error_handling.rb +79 -0
  104. data/proofs/expanded_object_inheritance.rb +82 -0
  105. data/proofs/partial_context_scoping_fix.rb +168 -0
  106. data/proofs/ui_context_partial_inheritance.rb +236 -0
  107. data/rhales.gemspec +14 -6
  108. data/schema_vs_data_comparison.md +254 -0
  109. data/test_direct_access.rb +36 -0
  110. metadata +142 -18
  111. data/CLAUDE.locale.txt +0 -7
  112. data/lib/rhales/context.rb +0 -240
  113. data/lib/rhales/hydration_data_aggregator.rb +0 -220
  114. data/lib/rhales/hydrator.rb +0 -141
  115. data/lib/rhales/parsers/handlebars-grammar-review.txt +0 -39
  116. data/lib/rhales/view.rb +0 -412
@@ -0,0 +1,197 @@
1
+ # lib/tasks/rhales_schema.rake
2
+
3
+ namespace :rhales do
4
+ namespace :schema do
5
+ desc 'Generate JSON Schemas from .rue template files'
6
+ task :generate do
7
+ require 'rhales'
8
+
9
+ # Default to current working directory (implementing project)
10
+ templates_dir = ENV.fetch('TEMPLATES_DIR', './templates')
11
+ output_dir = ENV.fetch('OUTPUT_DIR', './public/schemas')
12
+
13
+ puts "Schema Generation"
14
+ puts "=" * 60
15
+ puts "Templates: #{templates_dir}"
16
+ puts "Output: #{output_dir}"
17
+ puts "Zod: (using pnpm exec tsx)"
18
+ puts
19
+
20
+ # Validate templates directory exists
21
+ unless Dir.exist?(templates_dir)
22
+ puts "⚠️ Templates directory not found: #{templates_dir}"
23
+ puts
24
+ puts "Usage:"
25
+ puts " rake rhales:schema:generate TEMPLATES_DIR=./templates OUTPUT_DIR=./public/schemas"
26
+ puts
27
+ puts "Or from project root where templates/ exists:"
28
+ puts " rake rhales:schema:generate"
29
+ exit 1
30
+ end
31
+
32
+ # Extract schemas
33
+ extractor = Rhales::SchemaExtractor.new(templates_dir)
34
+ schemas = extractor.extract_all
35
+
36
+ if schemas.empty?
37
+ puts "⚠️ No schema sections found in templates"
38
+ puts
39
+ puts "Make sure your .rue files have <schema> sections:"
40
+ puts " <schema lang=\"js-zod\" window=\"appData\">"
41
+ puts " const schema = z.object({ ... });"
42
+ puts " </schema>"
43
+ exit 0
44
+ end
45
+
46
+ puts "Found #{schemas.size} schema section(s):"
47
+ schemas.each do |schema|
48
+ puts " - #{schema[:template_name]} (#{schema[:lang]})"
49
+ end
50
+ puts
51
+
52
+ # Generate JSON Schemas
53
+ generator = Rhales::SchemaGenerator.new(
54
+ templates_dir: templates_dir,
55
+ output_dir: output_dir
56
+ )
57
+
58
+ puts "Generating JSON Schemas..."
59
+ results = generator.generate_all
60
+
61
+ # Report results
62
+ puts
63
+ puts "Results:"
64
+ puts "-" * 60
65
+
66
+ generated_count = results[:generated]
67
+ failed_count = results[:failed]
68
+
69
+ if results[:success]
70
+ puts "✓ Successfully generated #{generated_count} schema(s)"
71
+ puts "✓ Output directory: #{output_dir}"
72
+ else
73
+ puts "✗ Generation failed with #{failed_count} error(s)"
74
+ results[:errors].each do |error|
75
+ puts " - #{error}"
76
+ end
77
+ end
78
+
79
+ puts
80
+
81
+ exit(results[:success] ? 0 : 1)
82
+ end
83
+
84
+ desc 'Validate existing JSON Schemas'
85
+ task :validate do
86
+ require 'rhales'
87
+ require 'json'
88
+ require 'json_schemer'
89
+
90
+ # Default to current working directory
91
+ schemas_dir = ENV.fetch('OUTPUT_DIR', './public/schemas')
92
+
93
+ unless Dir.exist?(schemas_dir)
94
+ puts "⚠️ Schemas directory not found: #{schemas_dir}"
95
+ puts
96
+ puts "Generate schemas first:"
97
+ puts " rake rhales:schema:generate"
98
+ exit 1
99
+ end
100
+
101
+ schema_files = Dir.glob("#{schemas_dir}/**/*.json")
102
+
103
+ if schema_files.empty?
104
+ puts "⚠️ No schema files found in #{schemas_dir}"
105
+ puts
106
+ puts "Generate schemas first:"
107
+ puts " rake rhales:schema:generate"
108
+ exit 1
109
+ end
110
+
111
+ puts "Validating #{schema_files.size} schema file(s) in #{schemas_dir}..."
112
+ puts
113
+
114
+ errors = []
115
+
116
+ schema_files.each do |file|
117
+ relative_path = file.sub("#{schemas_dir}/", '')
118
+
119
+ begin
120
+ schema = JSON.parse(File.read(file))
121
+
122
+ # Validate against JSON Schema meta-schema
123
+ unless schema.is_a?(Hash)
124
+ errors << "#{relative_path}: Not a valid object"
125
+ next
126
+ end
127
+
128
+ # Use JSONSchemer to validate against the meta-schema
129
+ meta_schema = JSONSchemer.schema(
130
+ {
131
+ '$schema' => 'https://json-schema.org/draft/2020-12/schema'
132
+ }
133
+ )
134
+
135
+ validation_errors = meta_schema.validate(schema).to_a
136
+
137
+ if validation_errors.any?
138
+ validation_errors.each do |error|
139
+ errors << "#{relative_path}: #{error['type']} at #{error['data_pointer']}"
140
+ end
141
+ else
142
+ puts "✓ #{relative_path}"
143
+ end
144
+ rescue JSON::ParserError => e
145
+ errors << "#{relative_path}: Invalid JSON - #{e.message}"
146
+ rescue => e
147
+ errors << "#{relative_path}: #{e.message}"
148
+ end
149
+ end
150
+
151
+ puts
152
+
153
+ if errors.any?
154
+ puts "Errors:"
155
+ errors.each { |err| puts " ✗ #{err}" }
156
+ exit 1
157
+ else
158
+ puts "All schemas valid ✓"
159
+ end
160
+ end
161
+
162
+ desc 'Show statistics about schema sections'
163
+ task :stats do
164
+ require 'rhales'
165
+
166
+ # Default to current working directory
167
+ templates_dir = ENV.fetch('TEMPLATES_DIR', './templates')
168
+
169
+ unless Dir.exist?(templates_dir)
170
+ puts "⚠️ Templates directory not found: #{templates_dir}"
171
+ puts
172
+ puts "Usage:"
173
+ puts " rake rhales:schema:stats TEMPLATES_DIR=./templates"
174
+ exit 1
175
+ end
176
+
177
+ extractor = Rhales::SchemaExtractor.new(templates_dir)
178
+ stats = extractor.schema_stats
179
+
180
+ puts "Schema Statistics"
181
+ puts "=" * 60
182
+ puts "Templates directory: #{templates_dir}"
183
+ puts
184
+ puts "Total .rue files: #{stats[:total_files]}"
185
+ puts "Files with <schema>: #{stats[:files_with_schemas]}"
186
+ puts "Files without <schema>: #{stats[:files_without_schemas]}"
187
+ puts
188
+
189
+ if stats[:schemas_by_lang].any?
190
+ puts "By language:"
191
+ stats[:schemas_by_lang].each do |lang, count|
192
+ puts " #{lang}: #{count}"
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
data/package.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "type": "module",
3
+ "dependencies": {
4
+ "zod": "^4.1.12"
5
+ },
6
+ "devDependencies": {
7
+ "@prettier/plugin-ruby": "^4.0.4",
8
+ "tsx": "^4.20.6"
9
+ }
10
+ }
data/pnpm-lock.yaml ADDED
@@ -0,0 +1,345 @@
1
+ lockfileVersion: '9.0'
2
+
3
+ settings:
4
+ autoInstallPeers: true
5
+ excludeLinksFromLockfile: false
6
+
7
+ importers:
8
+
9
+ .:
10
+ dependencies:
11
+ zod:
12
+ specifier: ^4.1.12
13
+ version: 4.1.12
14
+ devDependencies:
15
+ '@prettier/plugin-ruby':
16
+ specifier: ^4.0.4
17
+ version: 4.0.4(prettier@3.6.2)
18
+ tsx:
19
+ specifier: ^4.20.6
20
+ version: 4.20.6
21
+
22
+ packages:
23
+
24
+ '@esbuild/aix-ppc64@0.25.11':
25
+ resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==}
26
+ engines: {node: '>=18'}
27
+ cpu: [ppc64]
28
+ os: [aix]
29
+
30
+ '@esbuild/android-arm64@0.25.11':
31
+ resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==}
32
+ engines: {node: '>=18'}
33
+ cpu: [arm64]
34
+ os: [android]
35
+
36
+ '@esbuild/android-arm@0.25.11':
37
+ resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==}
38
+ engines: {node: '>=18'}
39
+ cpu: [arm]
40
+ os: [android]
41
+
42
+ '@esbuild/android-x64@0.25.11':
43
+ resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==}
44
+ engines: {node: '>=18'}
45
+ cpu: [x64]
46
+ os: [android]
47
+
48
+ '@esbuild/darwin-arm64@0.25.11':
49
+ resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==}
50
+ engines: {node: '>=18'}
51
+ cpu: [arm64]
52
+ os: [darwin]
53
+
54
+ '@esbuild/darwin-x64@0.25.11':
55
+ resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==}
56
+ engines: {node: '>=18'}
57
+ cpu: [x64]
58
+ os: [darwin]
59
+
60
+ '@esbuild/freebsd-arm64@0.25.11':
61
+ resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==}
62
+ engines: {node: '>=18'}
63
+ cpu: [arm64]
64
+ os: [freebsd]
65
+
66
+ '@esbuild/freebsd-x64@0.25.11':
67
+ resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==}
68
+ engines: {node: '>=18'}
69
+ cpu: [x64]
70
+ os: [freebsd]
71
+
72
+ '@esbuild/linux-arm64@0.25.11':
73
+ resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==}
74
+ engines: {node: '>=18'}
75
+ cpu: [arm64]
76
+ os: [linux]
77
+
78
+ '@esbuild/linux-arm@0.25.11':
79
+ resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==}
80
+ engines: {node: '>=18'}
81
+ cpu: [arm]
82
+ os: [linux]
83
+
84
+ '@esbuild/linux-ia32@0.25.11':
85
+ resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==}
86
+ engines: {node: '>=18'}
87
+ cpu: [ia32]
88
+ os: [linux]
89
+
90
+ '@esbuild/linux-loong64@0.25.11':
91
+ resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==}
92
+ engines: {node: '>=18'}
93
+ cpu: [loong64]
94
+ os: [linux]
95
+
96
+ '@esbuild/linux-mips64el@0.25.11':
97
+ resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==}
98
+ engines: {node: '>=18'}
99
+ cpu: [mips64el]
100
+ os: [linux]
101
+
102
+ '@esbuild/linux-ppc64@0.25.11':
103
+ resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==}
104
+ engines: {node: '>=18'}
105
+ cpu: [ppc64]
106
+ os: [linux]
107
+
108
+ '@esbuild/linux-riscv64@0.25.11':
109
+ resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==}
110
+ engines: {node: '>=18'}
111
+ cpu: [riscv64]
112
+ os: [linux]
113
+
114
+ '@esbuild/linux-s390x@0.25.11':
115
+ resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==}
116
+ engines: {node: '>=18'}
117
+ cpu: [s390x]
118
+ os: [linux]
119
+
120
+ '@esbuild/linux-x64@0.25.11':
121
+ resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==}
122
+ engines: {node: '>=18'}
123
+ cpu: [x64]
124
+ os: [linux]
125
+
126
+ '@esbuild/netbsd-arm64@0.25.11':
127
+ resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==}
128
+ engines: {node: '>=18'}
129
+ cpu: [arm64]
130
+ os: [netbsd]
131
+
132
+ '@esbuild/netbsd-x64@0.25.11':
133
+ resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==}
134
+ engines: {node: '>=18'}
135
+ cpu: [x64]
136
+ os: [netbsd]
137
+
138
+ '@esbuild/openbsd-arm64@0.25.11':
139
+ resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==}
140
+ engines: {node: '>=18'}
141
+ cpu: [arm64]
142
+ os: [openbsd]
143
+
144
+ '@esbuild/openbsd-x64@0.25.11':
145
+ resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==}
146
+ engines: {node: '>=18'}
147
+ cpu: [x64]
148
+ os: [openbsd]
149
+
150
+ '@esbuild/openharmony-arm64@0.25.11':
151
+ resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==}
152
+ engines: {node: '>=18'}
153
+ cpu: [arm64]
154
+ os: [openharmony]
155
+
156
+ '@esbuild/sunos-x64@0.25.11':
157
+ resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==}
158
+ engines: {node: '>=18'}
159
+ cpu: [x64]
160
+ os: [sunos]
161
+
162
+ '@esbuild/win32-arm64@0.25.11':
163
+ resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==}
164
+ engines: {node: '>=18'}
165
+ cpu: [arm64]
166
+ os: [win32]
167
+
168
+ '@esbuild/win32-ia32@0.25.11':
169
+ resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==}
170
+ engines: {node: '>=18'}
171
+ cpu: [ia32]
172
+ os: [win32]
173
+
174
+ '@esbuild/win32-x64@0.25.11':
175
+ resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==}
176
+ engines: {node: '>=18'}
177
+ cpu: [x64]
178
+ os: [win32]
179
+
180
+ '@prettier/plugin-ruby@4.0.4':
181
+ resolution: {integrity: sha512-lCpvfS/dQU5WrwN3AQ5vR8qrvj2h5gE41X08NNzAAXvHdM4zwwGRcP2sHSxfu6n6No+ljWCVx95NvJPFTTjCTg==}
182
+ peerDependencies:
183
+ prettier: ^3.0.0
184
+
185
+ esbuild@0.25.11:
186
+ resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==}
187
+ engines: {node: '>=18'}
188
+ hasBin: true
189
+
190
+ fsevents@2.3.3:
191
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
192
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
193
+ os: [darwin]
194
+
195
+ get-tsconfig@4.12.0:
196
+ resolution: {integrity: sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==}
197
+
198
+ prettier@3.6.2:
199
+ resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
200
+ engines: {node: '>=14'}
201
+ hasBin: true
202
+
203
+ resolve-pkg-maps@1.0.0:
204
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
205
+
206
+ tsx@4.20.6:
207
+ resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==}
208
+ engines: {node: '>=18.0.0'}
209
+ hasBin: true
210
+
211
+ zod@4.1.12:
212
+ resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==}
213
+
214
+ snapshots:
215
+
216
+ '@esbuild/aix-ppc64@0.25.11':
217
+ optional: true
218
+
219
+ '@esbuild/android-arm64@0.25.11':
220
+ optional: true
221
+
222
+ '@esbuild/android-arm@0.25.11':
223
+ optional: true
224
+
225
+ '@esbuild/android-x64@0.25.11':
226
+ optional: true
227
+
228
+ '@esbuild/darwin-arm64@0.25.11':
229
+ optional: true
230
+
231
+ '@esbuild/darwin-x64@0.25.11':
232
+ optional: true
233
+
234
+ '@esbuild/freebsd-arm64@0.25.11':
235
+ optional: true
236
+
237
+ '@esbuild/freebsd-x64@0.25.11':
238
+ optional: true
239
+
240
+ '@esbuild/linux-arm64@0.25.11':
241
+ optional: true
242
+
243
+ '@esbuild/linux-arm@0.25.11':
244
+ optional: true
245
+
246
+ '@esbuild/linux-ia32@0.25.11':
247
+ optional: true
248
+
249
+ '@esbuild/linux-loong64@0.25.11':
250
+ optional: true
251
+
252
+ '@esbuild/linux-mips64el@0.25.11':
253
+ optional: true
254
+
255
+ '@esbuild/linux-ppc64@0.25.11':
256
+ optional: true
257
+
258
+ '@esbuild/linux-riscv64@0.25.11':
259
+ optional: true
260
+
261
+ '@esbuild/linux-s390x@0.25.11':
262
+ optional: true
263
+
264
+ '@esbuild/linux-x64@0.25.11':
265
+ optional: true
266
+
267
+ '@esbuild/netbsd-arm64@0.25.11':
268
+ optional: true
269
+
270
+ '@esbuild/netbsd-x64@0.25.11':
271
+ optional: true
272
+
273
+ '@esbuild/openbsd-arm64@0.25.11':
274
+ optional: true
275
+
276
+ '@esbuild/openbsd-x64@0.25.11':
277
+ optional: true
278
+
279
+ '@esbuild/openharmony-arm64@0.25.11':
280
+ optional: true
281
+
282
+ '@esbuild/sunos-x64@0.25.11':
283
+ optional: true
284
+
285
+ '@esbuild/win32-arm64@0.25.11':
286
+ optional: true
287
+
288
+ '@esbuild/win32-ia32@0.25.11':
289
+ optional: true
290
+
291
+ '@esbuild/win32-x64@0.25.11':
292
+ optional: true
293
+
294
+ '@prettier/plugin-ruby@4.0.4(prettier@3.6.2)':
295
+ dependencies:
296
+ prettier: 3.6.2
297
+
298
+ esbuild@0.25.11:
299
+ optionalDependencies:
300
+ '@esbuild/aix-ppc64': 0.25.11
301
+ '@esbuild/android-arm': 0.25.11
302
+ '@esbuild/android-arm64': 0.25.11
303
+ '@esbuild/android-x64': 0.25.11
304
+ '@esbuild/darwin-arm64': 0.25.11
305
+ '@esbuild/darwin-x64': 0.25.11
306
+ '@esbuild/freebsd-arm64': 0.25.11
307
+ '@esbuild/freebsd-x64': 0.25.11
308
+ '@esbuild/linux-arm': 0.25.11
309
+ '@esbuild/linux-arm64': 0.25.11
310
+ '@esbuild/linux-ia32': 0.25.11
311
+ '@esbuild/linux-loong64': 0.25.11
312
+ '@esbuild/linux-mips64el': 0.25.11
313
+ '@esbuild/linux-ppc64': 0.25.11
314
+ '@esbuild/linux-riscv64': 0.25.11
315
+ '@esbuild/linux-s390x': 0.25.11
316
+ '@esbuild/linux-x64': 0.25.11
317
+ '@esbuild/netbsd-arm64': 0.25.11
318
+ '@esbuild/netbsd-x64': 0.25.11
319
+ '@esbuild/openbsd-arm64': 0.25.11
320
+ '@esbuild/openbsd-x64': 0.25.11
321
+ '@esbuild/openharmony-arm64': 0.25.11
322
+ '@esbuild/sunos-x64': 0.25.11
323
+ '@esbuild/win32-arm64': 0.25.11
324
+ '@esbuild/win32-ia32': 0.25.11
325
+ '@esbuild/win32-x64': 0.25.11
326
+
327
+ fsevents@2.3.3:
328
+ optional: true
329
+
330
+ get-tsconfig@4.12.0:
331
+ dependencies:
332
+ resolve-pkg-maps: 1.0.0
333
+
334
+ prettier@3.6.2: {}
335
+
336
+ resolve-pkg-maps@1.0.0: {}
337
+
338
+ tsx@4.20.6:
339
+ dependencies:
340
+ esbuild: 0.25.11
341
+ get-tsconfig: 4.12.0
342
+ optionalDependencies:
343
+ fsevents: 2.3.3
344
+
345
+ zod@4.1.12: {}
@@ -0,0 +1,2 @@
1
+ onlyBuiltDependencies:
2
+ - esbuild
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env ruby
2
+ # proofs/error_handling.rb
3
+
4
+ require_relative 'lib/rhales'
5
+
6
+ # Example demonstrating the new error hierarchy
7
+
8
+ puts '=== Rhales Error Hierarchy Demo ==='
9
+ puts
10
+
11
+ # 1. Catching all Rhales errors
12
+ begin
13
+ template = '{{#if user}}Hello{{else' # Missing closing {{/if}}
14
+ context = Rhales::Context.minimal(client: { user: 'John' })
15
+ Rhales::TemplateEngine.render(template, context)
16
+ rescue Rhales::Error => ex
17
+ puts "Caught any Rhales error: #{ex.class} - #{ex.message}"
18
+ end
19
+
20
+ puts
21
+
22
+ # 2. Catching render errors (which wrap parse errors)
23
+ begin
24
+ template = '{{unclosed'
25
+ context = Rhales::Context.minimal(client: {})
26
+ Rhales::TemplateEngine.render(template, context)
27
+ rescue Rhales::TemplateEngine::RenderError => ex
28
+ puts 'Render error wrapping parse error:'
29
+ puts " Class: #{ex.class}"
30
+ puts " Message: #{ex.message}"
31
+ end
32
+
33
+ puts
34
+
35
+ # 2b. Catching parse errors directly from parser
36
+ begin
37
+ parser = Rhales::HandlebarsParser.new('{{unclosed')
38
+ parser.parse!
39
+ rescue Rhales::ParseError => ex
40
+ puts 'Direct parse error details:'
41
+ puts " Class: #{ex.class}"
42
+ puts " Message: #{ex.message}"
43
+ puts " Source type: #{ex.source_type}"
44
+ puts " Line: #{ex.line}, Column: #{ex.column}"
45
+ end
46
+
47
+ puts
48
+
49
+ # 3. Validation error from Parser
50
+ begin
51
+ template = <<~RUE
52
+ <logic>
53
+ # Missing required sections
54
+ </logic>
55
+ RUE
56
+
57
+ parser = Rhales::RueDocument.new(template)
58
+ parser.parse!
59
+ rescue Rhales::ValidationError => ex
60
+ puts "Validation error: #{ex.class} - #{ex.message}"
61
+ end
62
+
63
+ puts
64
+
65
+ # 4. Render error example
66
+ begin
67
+ template = '{{> missing_partial}}'
68
+ context = Rhales::Context.minimal(client: {})
69
+ Rhales::TemplateEngine.render(template, context)
70
+ rescue Rhales::RenderError => ex
71
+ puts "Render error: #{ex.class} - #{ex.message}"
72
+ end
73
+
74
+ puts
75
+ puts '=== Benefits of the new hierarchy ==='
76
+ puts '1. Single rescue for all Rhales errors: rescue Rhales::Error'
77
+ puts '2. Stage-specific handling: ParseError, ValidationError, RenderError'
78
+ puts '3. Consistent error attributes across all parse errors'
79
+ puts '4. Better error messages with source context'