expressir 2.4.0 → 2.4.2

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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/TODO.bugs/01-stale-transformer-autoload.md +39 -0
  3. data/TODO.bugs/02-parser-class-instance-vars.md +36 -0
  4. data/TODO.bugs/03-builder-mutable-state.md +43 -0
  5. data/TODO.bugs/04-formatter-public-send-dispatch.md +53 -0
  6. data/TODO.bugs/05-anonymous-formatter-subclass.md +45 -0
  7. data/TODO.bugs/06-collection-registry-single-source.md +53 -0
  8. data/TODO.bugs/07-require-relative-cleanup.md +42 -0
  9. data/TODO.bugs/08-require-expressir-in-commands.md +34 -0
  10. data/TODO.bugs/09-parser-split.md +53 -0
  11. data/TODO.bugs/10-to-s-override.md +42 -0
  12. data/TODO.bugs/11-parser-class-variables.md +39 -0
  13. data/TODO.bugs/12-marker-modules-vs-registry.md +64 -0
  14. data/TODO.bugs/13-string-literal-scanner-limitation.md +52 -0
  15. data/TODO.bugs/14-model-formatting-leak.md +30 -0
  16. data/TODO.bugs/15-expression-children-macro.md +27 -0
  17. data/TODO.bugs/16-pretty-formatter-duplication.md +28 -0
  18. data/TODO.bugs/17-snake-case-cache-mutable-constant.md +28 -0
  19. data/TODO.bugs/18-const-get-private-constants.md +30 -0
  20. data/TODO.bugs/19-format-methods-public.md +22 -0
  21. data/TODO.bugs/20-coverage-nested-entities-dedup.md +20 -0
  22. data/TODO.bugs/21-operator-tokens-secondary-dispatch.md +21 -0
  23. data/TODO.bugs/22-builder-fast-path-wrappers.md +32 -0
  24. data/TODO.bugs/23-coverage-inverse-maps.md +21 -0
  25. data/TODO.bugs/24-streaming-builder-complexity.md +19 -0
  26. data/TODO.bugs/25-debug-puts-in-production.md +21 -0
  27. data/TODO.bugs/26-generic-entity-children-misplaced.md +21 -0
  28. data/TODO.bugs/27-package-build-god-method.md +19 -0
  29. data/TODO.bugs/28-package-god-class.md +30 -0
  30. data/TODO.bugs/29-validate-ascii-god-class.md +24 -0
  31. data/TODO.bugs/30-unicode-map-extraction.md +19 -0
  32. data/TODO.bugs/README.md +43 -0
  33. data/TODO.max-perf/01-restore-ci-green.md +29 -0
  34. data/TODO.max-perf/02-streaming-parse-path.md +31 -0
  35. data/TODO.max-perf/03-cli-parallel-opt-in.md +27 -0
  36. data/TODO.max-perf/04-benchmark-harness.md +28 -0
  37. data/TODO.max-perf/05-parallel-fidelity-specs.md +22 -0
  38. data/TODO.max-perf/06-builder-cpu-audit.md +41 -0
  39. data/TODO.max-perf/07-upstream-parsanol-roadmap.md +27 -0
  40. data/TODO.max-perf/08-builder-build-perf.md +45 -0
  41. data/TODO.max-perf/09-grammar-cold-start.md +25 -0
  42. data/TODO.max-perf/10-parser-facade-hygiene.md +23 -0
  43. data/TODO.max-perf/11-ci-green-closeout.md +25 -0
  44. data/TODO.max-perf/12-require-boot-profile.md +25 -0
  45. data/TODO.max-perf/13-key-conversion-specs.md +26 -0
  46. data/TODO.max-perf/14-builder-call-handler-audit.md +28 -0
  47. data/benchmark/srl_benchmark.rb +76 -17
  48. data/docs/_tutorials/formatting-schemas.adoc +89 -0
  49. data/docs/_tutorials/index.adoc +10 -0
  50. data/docs/lychee.toml +3 -0
  51. data/expressir.gemspec +4 -2
  52. data/lib/expressir/cli.rb +3 -0
  53. data/lib/expressir/commands/changes_import_eengine.rb +0 -6
  54. data/lib/expressir/commands/changes_validate.rb +0 -2
  55. data/lib/expressir/commands/clean.rb +1 -1
  56. data/lib/expressir/commands/coverage.rb +6 -2
  57. data/lib/expressir/commands/file_violations.rb +70 -0
  58. data/lib/expressir/commands/format.rb +1 -1
  59. data/lib/expressir/commands/non_ascii_character.rb +49 -0
  60. data/lib/expressir/commands/non_ascii_violation_collection.rb +301 -0
  61. data/lib/expressir/commands/package.rb +143 -187
  62. data/lib/expressir/commands/validate_ascii.rb +0 -510
  63. data/lib/expressir/commands/version.rb +1 -1
  64. data/lib/expressir/commands.rb +3 -0
  65. data/lib/expressir/coverage.rb +49 -117
  66. data/lib/expressir/express/ast_key_converter.rb +114 -0
  67. data/lib/expressir/express/builder.rb +71 -194
  68. data/lib/expressir/express/builder_context.rb +22 -0
  69. data/lib/expressir/express/builders/expression_builder.rb +16 -16
  70. data/lib/expressir/express/cache.rb +35 -8
  71. data/lib/expressir/express/error.rb +24 -0
  72. data/lib/expressir/express/formatter.rb +33 -18
  73. data/lib/expressir/express/formatters/declarations_formatter.rb +24 -2
  74. data/lib/expressir/express/formatters/remark_formatter.rb +75 -2
  75. data/lib/expressir/express/formatters/statements_formatter.rb +20 -3
  76. data/lib/expressir/express/grammar/parser.rb +705 -0
  77. data/lib/expressir/express/grammar.rb +11 -0
  78. data/lib/expressir/express/node_position_index.rb +215 -0
  79. data/lib/expressir/express/parallel_files.rb +229 -0
  80. data/lib/expressir/express/parser.rb +138 -950
  81. data/lib/expressir/express/pretty_formatter.rb +23 -5
  82. data/lib/expressir/express/remark_attacher.rb +497 -581
  83. data/lib/expressir/express/remark_scanner.rb +84 -19
  84. data/lib/expressir/express/schema_block_scanner.rb +137 -0
  85. data/lib/expressir/express/schema_source_formatter.rb +15 -0
  86. data/lib/expressir/express/scope_resolver.rb +223 -0
  87. data/lib/expressir/express/source_formatter.rb +15 -0
  88. data/lib/expressir/express/streaming_builder.rb +147 -176
  89. data/lib/expressir/express.rb +10 -6
  90. data/lib/expressir/model/concerns.rb +3 -0
  91. data/lib/expressir/model/data_types/generic_entity.rb +6 -6
  92. data/lib/expressir/model/declarations/entity.rb +5 -0
  93. data/lib/expressir/model/declarations/function.rb +5 -0
  94. data/lib/expressir/model/declarations/procedure.rb +5 -0
  95. data/lib/expressir/model/declarations/rule.rb +6 -0
  96. data/lib/expressir/model/declarations/schema.rb +21 -8
  97. data/lib/expressir/model/declarations/type.rb +3 -0
  98. data/lib/expressir/model/exp_file.rb +2 -0
  99. data/lib/expressir/model/expressions/aggregate_initializer.rb +1 -0
  100. data/lib/expressir/model/expressions/aggregate_initializer_item.rb +1 -0
  101. data/lib/expressir/model/expressions/binary_expression.rb +1 -0
  102. data/lib/expressir/model/expressions/entity_constructor.rb +1 -0
  103. data/lib/expressir/model/expressions/function_call.rb +1 -0
  104. data/lib/expressir/model/expressions/interval.rb +1 -0
  105. data/lib/expressir/model/expressions/query_expression.rb +2 -0
  106. data/lib/expressir/model/expressions/unary_expression.rb +1 -0
  107. data/lib/expressir/model/model_element.rb +133 -14
  108. data/lib/expressir/model/remark_format.rb +17 -0
  109. data/lib/expressir/model/remark_info.rb +31 -3
  110. data/lib/expressir/model/remark_placement.rb +29 -0
  111. data/lib/expressir/model/repository.rb +18 -5
  112. data/lib/expressir/model/statements/alias.rb +2 -0
  113. data/lib/expressir/model/statements/assignment.rb +4 -0
  114. data/lib/expressir/model/statements/case.rb +21 -0
  115. data/lib/expressir/model/statements/case_action.rb +1 -0
  116. data/lib/expressir/model/statements/compound.rb +4 -0
  117. data/lib/expressir/model/statements/escape.rb +3 -0
  118. data/lib/expressir/model/statements/if.rb +5 -0
  119. data/lib/expressir/model/statements/null.rb +3 -0
  120. data/lib/expressir/model/statements/procedure_call.rb +3 -0
  121. data/lib/expressir/model/statements/repeat.rb +3 -0
  122. data/lib/expressir/model/statements/return.rb +3 -0
  123. data/lib/expressir/model/statements/skip.rb +3 -0
  124. data/lib/expressir/model.rb +12 -3
  125. data/lib/expressir/package/builder.rb +2 -2
  126. data/lib/expressir/version.rb +6 -1
  127. data/lib/expressir.rb +56 -3
  128. metadata +81 -7
  129. data/lib/expressir/express/transformer/remark_handling.rb +0 -194
data/lib/expressir.rb CHANGED
@@ -1,6 +1,3 @@
1
- require_relative "expressir/version"
2
- require_relative "expressir/errors"
3
-
4
1
  require "lutaml/model"
5
2
  require "liquid" # To enable Lutaml::Model::Liquefiable
6
3
 
@@ -24,11 +21,67 @@ else
24
21
  end
25
22
 
26
23
  module Expressir
24
+ # yeptris mingw builds crash once loaded (`uninitialized constant
25
+ # Yeptris::FFI::NODE_SCALAR`, leptris/yeptris#318) and the gem rebinds
26
+ # core YAML on require, so merely having it in the bundle breaks every
27
+ # Hash#to_yaml on Windows. Pinning the portable adapters stops
28
+ # lutaml-model's bundle-based autodetection from loading yeptris there;
29
+ # other platforms keep the native engine. Revisit when yeptris ships a
30
+ # working mingw build.
31
+ def self.select_serialization_engines(windows: Gem.win_platform?)
32
+ return unless windows
33
+
34
+ Lutaml::Model::Config.configure do |config|
35
+ config.yaml_adapter_type = :standard
36
+ config.json_adapter_type = :standard
37
+ end
38
+ end
39
+
40
+ select_serialization_engines
41
+
27
42
  # Namespace modules - autoload loads the namespace file which contains
28
43
  # autoload definitions for classes within that namespace
29
44
  autoload :Config, "#{__dir__}/expressir/config"
30
45
  extend Config
31
46
 
47
+ autoload :Version, "#{__dir__}/expressir/version"
48
+
49
+ # Error classes — autoload the same errors.rb file from each name.
50
+ # The first reference triggers the load; the file defines all 21 classes.
51
+ autoload :Error, "#{__dir__}/expressir/errors"
52
+ autoload :FileNotFoundError, "#{__dir__}/expressir/errors"
53
+ autoload :ManifestNotFoundError, "#{__dir__}/expressir/errors"
54
+ autoload :PackageNotFoundError, "#{__dir__}/expressir/errors"
55
+ autoload :SchemaNotFoundError, "#{__dir__}/expressir/errors"
56
+ autoload :UsageError, "#{__dir__}/expressir/errors"
57
+ autoload :MissingRequiredArgumentError, "#{__dir__}/expressir/errors"
58
+ autoload :InvalidOptionError, "#{__dir__}/expressir/errors"
59
+ autoload :ValidationError, "#{__dir__}/expressir/errors"
60
+ autoload :ManifestValidationError, "#{__dir__}/expressir/errors"
61
+ autoload :SchemaValidationError, "#{__dir__}/expressir/errors"
62
+ autoload :ReferentialIntegrityError, "#{__dir__}/expressir/errors"
63
+ autoload :NoValidSchemaPathsError, "#{__dir__}/expressir/errors"
64
+ autoload :CommandError, "#{__dir__}/expressir/errors"
65
+ autoload :PackageBuildError, "#{__dir__}/expressir/errors"
66
+ autoload :PackageReadError, "#{__dir__}/expressir/errors"
67
+ autoload :PackageExtractError, "#{__dir__}/expressir/errors"
68
+ autoload :PackageValidationError, "#{__dir__}/expressir/errors"
69
+ autoload :PackageListError, "#{__dir__}/expressir/errors"
70
+ autoload :PackageSearchError, "#{__dir__}/expressir/errors"
71
+ autoload :PackageTreeError, "#{__dir__}/expressir/errors"
72
+
73
+ # Backward-compatible top-level VERSION constant.
74
+ # Expressir::VERSION is a string, which Ruby autoload cannot lazy-load
75
+ # (autoload only works for module/class constants). The actual value
76
+ # lives in Expressir::Version::VERSION, autoloaded on first reference.
77
+ # This const_missing triggers the autoload when Expressir::VERSION is
78
+ # referenced, then caches the result.
79
+ def self.const_missing(name)
80
+ return Version::VERSION if name == :VERSION
81
+
82
+ super
83
+ end
84
+
32
85
  autoload :Benchmark, "#{__dir__}/expressir/benchmark"
33
86
  autoload :Coverage, "#{__dir__}/expressir/coverage"
34
87
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: expressir
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-07-09 00:00:00.000000000 Z
11
+ date: 2026-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -174,16 +174,16 @@ dependencies:
174
174
  name: rubyzip
175
175
  requirement: !ruby/object:Gem::Requirement
176
176
  requirements:
177
- - - "~>"
177
+ - - ">="
178
178
  - !ruby/object:Gem::Version
179
- version: '2.3'
179
+ version: '0'
180
180
  type: :runtime
181
181
  prerelease: false
182
182
  version_requirements: !ruby/object:Gem::Requirement
183
183
  requirements:
184
- - - "~>"
184
+ - - ">="
185
185
  - !ruby/object:Gem::Version
186
- version: '2.3'
186
+ version: '0'
187
187
  - !ruby/object:Gem::Dependency
188
188
  name: table_tennis
189
189
  requirement: !ruby/object:Gem::Requirement
@@ -212,6 +212,20 @@ dependencies:
212
212
  - - "~>"
213
213
  - !ruby/object:Gem::Version
214
214
  version: '1.0'
215
+ - !ruby/object:Gem::Dependency
216
+ name: yeptris
217
+ requirement: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "~>"
220
+ - !ruby/object:Gem::Version
221
+ version: 0.6.1
222
+ type: :runtime
223
+ prerelease: false
224
+ version_requirements: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: 0.6.1
215
229
  description: Expressir ("EXPRESS in Ruby") is a Ruby parser for EXPRESS and a set
216
230
  of tools for accessing EXPRESS data models.
217
231
  email:
@@ -237,6 +251,51 @@ files:
237
251
  - Gemfile
238
252
  - README.adoc
239
253
  - Rakefile
254
+ - TODO.bugs/01-stale-transformer-autoload.md
255
+ - TODO.bugs/02-parser-class-instance-vars.md
256
+ - TODO.bugs/03-builder-mutable-state.md
257
+ - TODO.bugs/04-formatter-public-send-dispatch.md
258
+ - TODO.bugs/05-anonymous-formatter-subclass.md
259
+ - TODO.bugs/06-collection-registry-single-source.md
260
+ - TODO.bugs/07-require-relative-cleanup.md
261
+ - TODO.bugs/08-require-expressir-in-commands.md
262
+ - TODO.bugs/09-parser-split.md
263
+ - TODO.bugs/10-to-s-override.md
264
+ - TODO.bugs/11-parser-class-variables.md
265
+ - TODO.bugs/12-marker-modules-vs-registry.md
266
+ - TODO.bugs/13-string-literal-scanner-limitation.md
267
+ - TODO.bugs/14-model-formatting-leak.md
268
+ - TODO.bugs/15-expression-children-macro.md
269
+ - TODO.bugs/16-pretty-formatter-duplication.md
270
+ - TODO.bugs/17-snake-case-cache-mutable-constant.md
271
+ - TODO.bugs/18-const-get-private-constants.md
272
+ - TODO.bugs/19-format-methods-public.md
273
+ - TODO.bugs/20-coverage-nested-entities-dedup.md
274
+ - TODO.bugs/21-operator-tokens-secondary-dispatch.md
275
+ - TODO.bugs/22-builder-fast-path-wrappers.md
276
+ - TODO.bugs/23-coverage-inverse-maps.md
277
+ - TODO.bugs/24-streaming-builder-complexity.md
278
+ - TODO.bugs/25-debug-puts-in-production.md
279
+ - TODO.bugs/26-generic-entity-children-misplaced.md
280
+ - TODO.bugs/27-package-build-god-method.md
281
+ - TODO.bugs/28-package-god-class.md
282
+ - TODO.bugs/29-validate-ascii-god-class.md
283
+ - TODO.bugs/30-unicode-map-extraction.md
284
+ - TODO.bugs/README.md
285
+ - TODO.max-perf/01-restore-ci-green.md
286
+ - TODO.max-perf/02-streaming-parse-path.md
287
+ - TODO.max-perf/03-cli-parallel-opt-in.md
288
+ - TODO.max-perf/04-benchmark-harness.md
289
+ - TODO.max-perf/05-parallel-fidelity-specs.md
290
+ - TODO.max-perf/06-builder-cpu-audit.md
291
+ - TODO.max-perf/07-upstream-parsanol-roadmap.md
292
+ - TODO.max-perf/08-builder-build-perf.md
293
+ - TODO.max-perf/09-grammar-cold-start.md
294
+ - TODO.max-perf/10-parser-facade-hygiene.md
295
+ - TODO.max-perf/11-ci-green-closeout.md
296
+ - TODO.max-perf/12-require-boot-profile.md
297
+ - TODO.max-perf/13-key-conversion-specs.md
298
+ - TODO.max-perf/14-builder-call-handler-audit.md
240
299
  - benchmark/srl_benchmark.rb
241
300
  - benchmark/srl_native_benchmark.rb
242
301
  - benchmark/srl_ruby_benchmark.rb
@@ -291,6 +350,7 @@ files:
291
350
  - docs/_references/index.adoc
292
351
  - docs/_tutorials/creating-ler-package.adoc
293
352
  - docs/_tutorials/documentation-coverage.adoc
353
+ - docs/_tutorials/formatting-schemas.adoc
294
354
  - docs/_tutorials/index.adoc
295
355
  - docs/_tutorials/liquid-templates.adoc
296
356
  - docs/_tutorials/parsing-your-first-schema.adoc
@@ -331,8 +391,11 @@ files:
331
391
  - lib/expressir/commands/changes_validate.rb
332
392
  - lib/expressir/commands/clean.rb
333
393
  - lib/expressir/commands/coverage.rb
394
+ - lib/expressir/commands/file_violations.rb
334
395
  - lib/expressir/commands/format.rb
335
396
  - lib/expressir/commands/manifest.rb
397
+ - lib/expressir/commands/non_ascii_character.rb
398
+ - lib/expressir/commands/non_ascii_violation_collection.rb
336
399
  - lib/expressir/commands/package.rb
337
400
  - lib/expressir/commands/validate.rb
338
401
  - lib/expressir/commands/validate_ascii.rb
@@ -348,7 +411,9 @@ files:
348
411
  - lib/expressir/eengine/modified_object.rb
349
412
  - lib/expressir/errors.rb
350
413
  - lib/expressir/express.rb
414
+ - lib/expressir/express/ast_key_converter.rb
351
415
  - lib/expressir/express/builder.rb
416
+ - lib/expressir/express/builder_context.rb
352
417
  - lib/expressir/express/builder_registry.rb
353
418
  - lib/expressir/express/builders.rb
354
419
  - lib/expressir/express/builders/attribute_decl_builder.rb
@@ -397,17 +462,24 @@ files:
397
462
  - lib/expressir/express/formatters/remark_item_formatter.rb
398
463
  - lib/expressir/express/formatters/statements_formatter.rb
399
464
  - lib/expressir/express/formatters/supertype_expressions_formatter.rb
465
+ - lib/expressir/express/grammar.rb
466
+ - lib/expressir/express/grammar/parser.rb
400
467
  - lib/expressir/express/hyperlink_formatter.rb
401
468
  - lib/expressir/express/line_map.rb
402
469
  - lib/expressir/express/model_visitor.rb
470
+ - lib/expressir/express/node_position_index.rb
471
+ - lib/expressir/express/parallel_files.rb
403
472
  - lib/expressir/express/parser.rb
404
473
  - lib/expressir/express/pretty_formatter.rb
405
474
  - lib/expressir/express/remark_attacher.rb
406
475
  - lib/expressir/express/remark_scanner.rb
407
476
  - lib/expressir/express/resolve_references_model_visitor.rb
477
+ - lib/expressir/express/schema_block_scanner.rb
408
478
  - lib/expressir/express/schema_head_formatter.rb
479
+ - lib/expressir/express/schema_source_formatter.rb
480
+ - lib/expressir/express/scope_resolver.rb
481
+ - lib/expressir/express/source_formatter.rb
409
482
  - lib/expressir/express/streaming_builder.rb
410
- - lib/expressir/express/transformer/remark_handling.rb
411
483
  - lib/expressir/liquid.rb
412
484
  - lib/expressir/manifest.rb
413
485
  - lib/expressir/manifest/resolver.rb
@@ -485,7 +557,9 @@ files:
485
557
  - lib/expressir/model/references/group_reference.rb
486
558
  - lib/expressir/model/references/index_reference.rb
487
559
  - lib/expressir/model/references/simple_reference.rb
560
+ - lib/expressir/model/remark_format.rb
488
561
  - lib/expressir/model/remark_info.rb
562
+ - lib/expressir/model/remark_placement.rb
489
563
  - lib/expressir/model/repository.rb
490
564
  - lib/expressir/model/repository_validator.rb
491
565
  - lib/expressir/model/search_engine.rb
@@ -1,194 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "parsanol"
4
-
5
- module Expressir
6
- module Express
7
- # Handles remark extraction and attachment for the Transformer.
8
- # Works with the AST directly, without needing Ctx objects.
9
- module RemarkHandling
10
- extend self
11
-
12
- # Extract all remarks from the AST with their tags and source positions.
13
- # @param ast [Hash] The AST from Parsanol parser
14
- # @param source [String] The original source code
15
- # @return [Array<Hash>] Array of remark info hashes
16
- def extract_remarks(ast, source)
17
- remarks = []
18
-
19
- # Extract embedded remarks (*...*)
20
- extract_embedded_remarks(ast, source, remarks)
21
-
22
- # Extract tail remarks (--...)
23
- extract_tail_remarks(ast, source, remarks)
24
-
25
- remarks
26
- end
27
-
28
- # Attach remarks to model elements based on their tagged paths.
29
- # @param model [Model::ModelElement] The root model element
30
- # @param remarks [Array<Hash>] The extracted remarks
31
- def attach_remarks(model, remarks)
32
- # Group remarks by their tag
33
- tagged_remarks, untagged_remarks = remarks.partition { |r| r[:tag] }
34
-
35
- # Process tagged remarks
36
- tagged_remarks.each do |remark|
37
- target = find_by_path(model, remark[:tag])
38
- if target
39
- add_remark(target, remark[:text])
40
- end
41
- end
42
-
43
- # Process untagged remarks (attach based on position)
44
- attach_untagged_remarks(model, untagged_remarks)
45
- end
46
-
47
- private
48
-
49
- def extract_embedded_remarks(ast, source, remarks, depth = 0)
50
- return if depth > 50 # Prevent infinite recursion
51
-
52
- case ast
53
- when Hash
54
- ast.each do |key, value|
55
- if key == :embeddedRemark
56
- extract_single_embedded_remark(value, source, remarks)
57
- else
58
- extract_embedded_remarks(value, source, remarks, depth + 1)
59
- end
60
- end
61
- when Array
62
- ast.each do |item|
63
- extract_embedded_remarks(item, source, remarks, depth + 1)
64
- end
65
- end
66
- end
67
-
68
- def extract_single_embedded_remark(data, source, remarks)
69
- return unless data
70
-
71
- # Find the slice to get position
72
- slice = find_slice(data)
73
- return unless slice
74
-
75
- # Extract content from the source
76
- content = source[slice.offset...(slice.offset + slice.length)]
77
- return unless content
78
-
79
- # Remove (* and *) delimiters
80
- if content =~ /^\(\*(.*?)\*\)$/m
81
- inner_content = $1.strip
82
- tag, text = parse_tagged_content(inner_content)
83
-
84
- remarks << {
85
- position: slice.offset,
86
- tag: tag,
87
- text: text,
88
- format: :embedded,
89
- }
90
- end
91
- end
92
-
93
- def extract_tail_remarks(ast, source, remarks, depth = 0)
94
- return if depth > 50
95
-
96
- case ast
97
- when Hash
98
- ast.each do |key, value|
99
- if key == :tailRemark
100
- extract_single_tail_remark(value, source, remarks)
101
- else
102
- extract_tail_remarks(value, source, remarks, depth + 1)
103
- end
104
- end
105
- when Array
106
- ast.each do |item|
107
- extract_tail_remarks(item, source, remarks, depth + 1)
108
- end
109
- end
110
- end
111
-
112
- def extract_single_tail_remark(data, source, remarks)
113
- return unless data
114
-
115
- # Find the slice to get position
116
- slice = find_slice(data)
117
- return unless slice
118
-
119
- # Extract content from the source
120
- content = source[slice.offset...(slice.offset + slice.length)]
121
- return unless content
122
-
123
- # Remove -- prefix and any trailing newline
124
- if content =~ /^--\s*(.*?)(?:\n|$)/m
125
- remark_text = $1.strip
126
- tag, text = parse_tagged_content(remark_text)
127
-
128
- remarks << {
129
- position: slice.offset,
130
- tag: tag,
131
- text: text,
132
- format: :tail,
133
- }
134
- end
135
- end
136
-
137
- def find_slice(data, depth = 0)
138
- return nil if depth > 10
139
-
140
- case data
141
- when Hash
142
- data.each_value do |value|
143
- return value if value.is_a?(Parsanol::Slice)
144
-
145
- result = find_slice(value, depth + 1)
146
- return result if result
147
- end
148
- when Array
149
- data.each do |item|
150
- result = find_slice(item, depth + 1)
151
- return result if result
152
- end
153
- end
154
- nil
155
- end
156
-
157
- def parse_tagged_content(content)
158
- if content =~ /^"([^"]+)"\s*(.*)$/m
159
- [$1, $2.strip]
160
- else
161
- [nil, content.strip]
162
- end
163
- end
164
-
165
- def find_by_path(model, path)
166
- return nil unless path
167
- return nil unless model.is_a?(Model::ModelElement)
168
-
169
- # Handle paths with colons (like "wr:WR1" for where rules)
170
- normalized_path = path.gsub(":", ".")
171
-
172
- begin
173
- model.find(normalized_path)
174
- rescue StandardError
175
- nil
176
- end
177
- end
178
-
179
- def add_remark(node, text)
180
- return unless node
181
- return unless node.is_a?(Model::ModelElement)
182
-
183
- node.remarks ||= []
184
- node.remarks << text
185
- end
186
-
187
- def attach_untagged_remarks(model, remarks)
188
- # For untagged remarks, we need to find nearby nodes
189
- # This is more complex and may require source position tracking
190
- # For now, skip untagged remarks as they are less common
191
- end
192
- end
193
- end
194
- end