expressir 1.2.11-aarch64-linux → 2.4.29-aarch64-linux

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 (467) hide show
  1. checksums.yaml +4 -4
  2. data/.cargo/config.toml +3 -0
  3. data/.github/scripts/test_installed_gem.rb +34 -0
  4. data/.github/workflows/codeql.yml +35 -0
  5. data/.github/workflows/docs.yml +99 -0
  6. data/.github/workflows/links.yml +100 -0
  7. data/.github/workflows/native-gems.yml +201 -0
  8. data/.github/workflows/rake.yml +10 -296
  9. data/.github/workflows/release.yml +26 -114
  10. data/.github/workflows/rust-ext.yml +41 -0
  11. data/.github/workflows/stress.yml +36 -0
  12. data/.github/workflows/validate_schemas.yml +48 -0
  13. data/.github/workflows/verify_remarks.yml +33 -0
  14. data/.gitignore +33 -1
  15. data/.rubocop.yml +11 -11
  16. data/.rubocop_todo.yml +297 -0
  17. data/CHANGELOG.md +159 -0
  18. data/Gemfile +15 -1
  19. data/README.adoc +2675 -47
  20. data/Rakefile +34 -10
  21. data/TODO.bugs/01-stale-transformer-autoload.md +39 -0
  22. data/TODO.bugs/02-parser-class-instance-vars.md +36 -0
  23. data/TODO.bugs/03-builder-mutable-state.md +43 -0
  24. data/TODO.bugs/04-formatter-public-send-dispatch.md +53 -0
  25. data/TODO.bugs/05-anonymous-formatter-subclass.md +45 -0
  26. data/TODO.bugs/06-collection-registry-single-source.md +53 -0
  27. data/TODO.bugs/07-require-relative-cleanup.md +42 -0
  28. data/TODO.bugs/08-require-expressir-in-commands.md +34 -0
  29. data/TODO.bugs/09-parser-split.md +53 -0
  30. data/TODO.bugs/10-to-s-override.md +42 -0
  31. data/TODO.bugs/11-parser-class-variables.md +39 -0
  32. data/TODO.bugs/12-marker-modules-vs-registry.md +64 -0
  33. data/TODO.bugs/13-string-literal-scanner-limitation.md +52 -0
  34. data/TODO.bugs/14-model-formatting-leak.md +30 -0
  35. data/TODO.bugs/15-expression-children-macro.md +27 -0
  36. data/TODO.bugs/16-pretty-formatter-duplication.md +28 -0
  37. data/TODO.bugs/17-snake-case-cache-mutable-constant.md +28 -0
  38. data/TODO.bugs/18-const-get-private-constants.md +30 -0
  39. data/TODO.bugs/19-format-methods-public.md +22 -0
  40. data/TODO.bugs/20-coverage-nested-entities-dedup.md +20 -0
  41. data/TODO.bugs/21-operator-tokens-secondary-dispatch.md +21 -0
  42. data/TODO.bugs/22-builder-fast-path-wrappers.md +32 -0
  43. data/TODO.bugs/23-coverage-inverse-maps.md +21 -0
  44. data/TODO.bugs/24-streaming-builder-complexity.md +19 -0
  45. data/TODO.bugs/25-debug-puts-in-production.md +21 -0
  46. data/TODO.bugs/26-generic-entity-children-misplaced.md +21 -0
  47. data/TODO.bugs/27-package-build-god-method.md +19 -0
  48. data/TODO.bugs/28-package-god-class.md +30 -0
  49. data/TODO.bugs/29-validate-ascii-god-class.md +24 -0
  50. data/TODO.bugs/30-unicode-map-extraction.md +19 -0
  51. data/TODO.bugs/README.md +43 -0
  52. data/TODO.max-perf/01-restore-ci-green.md +36 -0
  53. data/TODO.max-perf/02-streaming-parse-path.md +31 -0
  54. data/TODO.max-perf/03-cli-parallel-opt-in.md +27 -0
  55. data/TODO.max-perf/04-benchmark-harness.md +28 -0
  56. data/TODO.max-perf/05-parallel-fidelity-specs.md +22 -0
  57. data/TODO.max-perf/06-builder-cpu-audit.md +41 -0
  58. data/TODO.max-perf/07-upstream-parsanol-roadmap.md +27 -0
  59. data/TODO.max-perf/08-builder-build-perf.md +45 -0
  60. data/TODO.max-perf/09-grammar-cold-start.md +25 -0
  61. data/TODO.max-perf/10-parser-facade-hygiene.md +23 -0
  62. data/TODO.max-perf/11-ci-green-closeout.md +25 -0
  63. data/TODO.max-perf/12-require-boot-profile.md +25 -0
  64. data/TODO.max-perf/13-key-conversion-specs.md +26 -0
  65. data/TODO.max-perf/14-builder-call-handler-audit.md +28 -0
  66. data/TODO.parity-ee/00-overview.md +76 -0
  67. data/TODO.parity-ee/01-annex-g-rule-extraction.md +41 -0
  68. data/TODO.parity-ee/02-eeng-algorithm-inventory.md +8 -0
  69. data/TODO.parity-ee/03-eeng-oracle-harness.md +33 -0
  70. data/TODO.parity-ee/04-shtolo-concatenate.md +44 -0
  71. data/TODO.parity-ee/05-shtolo-longform-flatten.md +53 -0
  72. data/TODO.parity-ee/06-interface-scheduling-parity.md +47 -0
  73. data/TODO.parity-ee/07-semantic-checks-port.md +35 -0
  74. data/TODO.parity-ee/08-pretty-roundtrip-gate.md +27 -0
  75. data/TODO.parity-ee/09-smrl-index-and-listing.md +22 -0
  76. data/TODO.parity-ee/10-interface-dot-graph.md +21 -0
  77. data/TODO.parity-ee/11-import-eeng-tests.md +79 -0
  78. data/TODO.parity-ee/12-full-check-catalog.md +67 -0
  79. data/TODO.parity-ee/13-population-p21.md +54 -0
  80. data/TODO.parity-ee/14-shtolo-completion.md +44 -0
  81. data/TODO.parity-ee/15-part28-xml.md +51 -0
  82. data/TODO.parity-ee/16-compare-patch.md +48 -0
  83. data/TODO.parity-ee/17-official-tests.md +42 -0
  84. data/TODO.parity-ee/18-mim-mapping.md +47 -0
  85. data/TODO.parity-ee/19-architecture.md +97 -0
  86. data/TODO.parity-ee/parity-matrix.md +108 -0
  87. data/TODO.refpath-v2/00-overview.md +64 -0
  88. data/TODO.suma-improvements/00-overview.md +23 -0
  89. data/TODO.suma-improvements/01-prebuilt-platform-gems.md +33 -0
  90. data/TODO.suma-improvements/02-suma-e2e.md +39 -0
  91. data/TODO.suma-improvements/03-item-graph.md +22 -0
  92. data/TODO.suma-improvements/04-compiled-set-default.md +16 -0
  93. data/TODO.suma-improvements/05-validation-in-docs.md +17 -0
  94. data/TODO.suma-improvements/06-memory-remeasure.md +36 -0
  95. data/TODO.suma-improvements/07-part28-xml.md +15 -0
  96. data/TODO.suma-improvements/08-windows-gnu-toolchain.md +15 -0
  97. data/TODO.suma-improvements/09-checker-tranche3.md +13 -0
  98. data/TODO.suma-improvements/10-expressdoc.md +8 -0
  99. data/benchmark/srl_benchmark.rb +458 -0
  100. data/benchmark/srl_native_benchmark.rb +146 -0
  101. data/benchmark/srl_ruby_benchmark.rb +132 -0
  102. data/bin/rspec +2 -1
  103. data/docs/Gemfile +12 -0
  104. data/docs/_config.yml +141 -0
  105. data/docs/_guides/changes/changes-format.adoc +778 -0
  106. data/docs/_guides/changes/importing-eengine.adoc +898 -0
  107. data/docs/_guides/changes/index.adoc +396 -0
  108. data/docs/_guides/changes/programmatic-usage.adoc +1038 -0
  109. data/docs/_guides/changes/validating-changes.adoc +681 -0
  110. data/docs/_guides/cli/benchmark-performance.adoc +834 -0
  111. data/docs/_guides/cli/coverage-analysis.adoc +921 -0
  112. data/docs/_guides/cli/format-schemas.adoc +547 -0
  113. data/docs/_guides/cli/index.adoc +8 -0
  114. data/docs/_guides/cli/managing-changes.adoc +927 -0
  115. data/docs/_guides/cli/validate-ascii.adoc +645 -0
  116. data/docs/_guides/cli/validate-schemas.adoc +534 -0
  117. data/docs/_guides/formatter/formatter-architecture.adoc +401 -0
  118. data/docs/_guides/index.adoc +165 -0
  119. data/docs/_guides/ler/creating-packages.adoc +664 -0
  120. data/docs/_guides/ler/index.adoc +305 -0
  121. data/docs/_guides/ler/loading-packages.adoc +707 -0
  122. data/docs/_guides/ler/package-formats.adoc +748 -0
  123. data/docs/_guides/ler/querying-packages.adoc +826 -0
  124. data/docs/_guides/ler/step-packages.adoc +385 -0
  125. data/docs/_guides/ler/validating-packages.adoc +750 -0
  126. data/docs/_guides/liquid/basic-templates.adoc +813 -0
  127. data/docs/_guides/liquid/documentation-generation.adoc +1042 -0
  128. data/docs/_guides/liquid/drops-reference.adoc +829 -0
  129. data/docs/_guides/liquid/filters-and-tags.adoc +912 -0
  130. data/docs/_guides/liquid/index.adoc +468 -0
  131. data/docs/_guides/manifests/creating-manifests.adoc +483 -0
  132. data/docs/_guides/manifests/index.adoc +307 -0
  133. data/docs/_guides/manifests/resolving-manifests.adoc +557 -0
  134. data/docs/_guides/manifests/validating-manifests.adoc +713 -0
  135. data/docs/_guides/ruby-api/formatting-schemas.adoc +605 -0
  136. data/docs/_guides/ruby-api/index.adoc +257 -0
  137. data/docs/_guides/ruby-api/parsing-files.adoc +421 -0
  138. data/docs/_guides/ruby-api/search-engine.adoc +609 -0
  139. data/docs/_guides/ruby-api/working-with-repository.adoc +577 -0
  140. data/docs/_pages/data-model.adoc +665 -0
  141. data/docs/_pages/express-language.adoc +506 -0
  142. data/docs/_pages/getting-started.adoc +414 -0
  143. data/docs/_pages/index.adoc +116 -0
  144. data/docs/_pages/introduction.adoc +256 -0
  145. data/docs/_pages/ler-packages.adoc +837 -0
  146. data/docs/_pages/parsers.adoc +709 -0
  147. data/docs/_pages/schema-manifests.adoc +431 -0
  148. data/docs/_references/index.adoc +228 -0
  149. data/docs/_tutorials/creating-ler-package.adoc +735 -0
  150. data/docs/_tutorials/documentation-coverage.adoc +795 -0
  151. data/docs/_tutorials/formatting-schemas.adoc +89 -0
  152. data/docs/_tutorials/index.adoc +231 -0
  153. data/docs/_tutorials/liquid-templates.adoc +806 -0
  154. data/docs/_tutorials/parsing-your-first-schema.adoc +522 -0
  155. data/docs/_tutorials/querying-schemas.adoc +751 -0
  156. data/docs/_tutorials/working-with-multiple-schemas.adoc +676 -0
  157. data/docs/index.adoc +242 -0
  158. data/docs/lychee.toml +90 -0
  159. data/examples/demo_ler_usage.sh +86 -0
  160. data/examples/ler/README.md +111 -0
  161. data/examples/ler/simple_example.ler +0 -0
  162. data/examples/ler/simple_schema.exp +33 -0
  163. data/examples/ler_build.rb +75 -0
  164. data/examples/ler_cli.rb +79 -0
  165. data/examples/ler_demo_complete.rb +276 -0
  166. data/examples/ler_query.rb +91 -0
  167. data/examples/ler_query_examples.rb +305 -0
  168. data/examples/ler_stats.rb +81 -0
  169. data/examples/phase3_demo.rb +159 -0
  170. data/examples/query_demo_simple.rb +131 -0
  171. data/exe/expressir +6 -17
  172. data/exe/expressir-format +14 -0
  173. data/exe/{format-test → expressir-format-test} +8 -7
  174. data/expressir.gemspec +50 -37
  175. data/lib/expressir/3.2/expressir_core.so +0 -0
  176. data/lib/expressir/3.3/expressir_core.so +0 -0
  177. data/lib/expressir/3.4/expressir_core.so +0 -0
  178. data/lib/expressir/4.0/expressir_core.so +0 -0
  179. data/lib/expressir/benchmark.rb +310 -0
  180. data/lib/expressir/changes/item_change.rb +20 -0
  181. data/lib/expressir/changes/mapping_change.rb +16 -0
  182. data/lib/expressir/changes/schema_change.rb +85 -0
  183. data/lib/expressir/changes/version_change.rb +26 -0
  184. data/lib/expressir/changes.rb +9 -0
  185. data/lib/expressir/cli.rb +138 -11
  186. data/lib/expressir/commands/base.rb +25 -0
  187. data/lib/expressir/commands/benchmark.rb +59 -0
  188. data/lib/expressir/commands/benchmark_cache.rb +80 -0
  189. data/lib/expressir/commands/changes.rb +34 -0
  190. data/lib/expressir/commands/changes_import_eengine.rb +146 -0
  191. data/lib/expressir/commands/changes_validate.rb +63 -0
  192. data/lib/expressir/commands/check.rb +56 -0
  193. data/lib/expressir/commands/clean.rb +20 -0
  194. data/lib/expressir/commands/coverage.rb +458 -0
  195. data/lib/expressir/commands/expand.rb +26 -0
  196. data/lib/expressir/commands/file_violations.rb +70 -0
  197. data/lib/expressir/commands/fix.rb +33 -0
  198. data/lib/expressir/commands/flatten.rb +29 -0
  199. data/lib/expressir/commands/format.rb +43 -0
  200. data/lib/expressir/commands/manifest.rb +420 -0
  201. data/lib/expressir/commands/mapping_validate.rb +68 -0
  202. data/lib/expressir/commands/non_ascii_character.rb +49 -0
  203. data/lib/expressir/commands/non_ascii_violation_collection.rb +301 -0
  204. data/lib/expressir/commands/package.rb +1222 -0
  205. data/lib/expressir/commands/parity_inputs.rb +160 -0
  206. data/lib/expressir/commands/validate.rb +106 -0
  207. data/lib/expressir/commands/validate_ascii.rb +94 -0
  208. data/lib/expressir/commands/validate_load.rb +91 -0
  209. data/lib/expressir/commands/version.rb +9 -0
  210. data/lib/expressir/commands/xsd.rb +23 -0
  211. data/lib/expressir/commands.rb +30 -0
  212. data/lib/expressir/config.rb +40 -3
  213. data/lib/expressir/coverage.rb +510 -0
  214. data/lib/expressir/eengine/arm_compare_report.rb +23 -0
  215. data/lib/expressir/eengine/changes_section.rb +16 -0
  216. data/lib/expressir/eengine/compare_report.rb +69 -0
  217. data/lib/expressir/eengine/mim_compare_report.rb +23 -0
  218. data/lib/expressir/eengine/modified_object.rb +21 -0
  219. data/lib/expressir/eengine.rb +9 -0
  220. data/lib/expressir/errors.rb +113 -0
  221. data/lib/expressir/express/adoc_hyperlink_formatter.rb +30 -0
  222. data/lib/expressir/express/adoc_source_formatter.rb +12 -0
  223. data/lib/expressir/express/ast_key_converter.rb +114 -0
  224. data/lib/expressir/express/builder.rb +277 -0
  225. data/lib/expressir/express/builder_context.rb +22 -0
  226. data/lib/expressir/express/builder_registry.rb +397 -0
  227. data/lib/expressir/express/builders/attribute_decl_builder.rb +32 -0
  228. data/lib/expressir/express/builders/built_in_builder.rb +75 -0
  229. data/lib/expressir/express/builders/constant_builder.rb +108 -0
  230. data/lib/expressir/express/builders/declaration_builder.rb +20 -0
  231. data/lib/expressir/express/builders/derive_clause_builder.rb +14 -0
  232. data/lib/expressir/express/builders/derived_attr_builder.rb +28 -0
  233. data/lib/expressir/express/builders/domain_rule_builder.rb +21 -0
  234. data/lib/expressir/express/builders/entity_decl_builder.rb +116 -0
  235. data/lib/expressir/express/builders/explicit_attr_builder.rb +49 -0
  236. data/lib/expressir/express/builders/expression_builder.rb +416 -0
  237. data/lib/expressir/express/builders/function_decl_builder.rb +86 -0
  238. data/lib/expressir/express/builders/helpers.rb +148 -0
  239. data/lib/expressir/express/builders/interface_builder.rb +151 -0
  240. data/lib/expressir/express/builders/inverse_attr_builder.rb +43 -0
  241. data/lib/expressir/express/builders/inverse_attr_type_builder.rb +30 -0
  242. data/lib/expressir/express/builders/inverse_clause_builder.rb +14 -0
  243. data/lib/expressir/express/builders/literal_builder.rb +93 -0
  244. data/lib/expressir/express/builders/procedure_decl_builder.rb +82 -0
  245. data/lib/expressir/express/builders/qualifier_builder.rb +102 -0
  246. data/lib/expressir/express/builders/reference_builder.rb +18 -0
  247. data/lib/expressir/express/builders/rule_decl_builder.rb +97 -0
  248. data/lib/expressir/express/builders/schema_body_decl_builder.rb +18 -0
  249. data/lib/expressir/express/builders/schema_decl_builder.rb +56 -0
  250. data/lib/expressir/express/builders/schema_version_builder.rb +34 -0
  251. data/lib/expressir/express/builders/simple_id_builder.rb +17 -0
  252. data/lib/expressir/express/builders/statement_builder.rb +243 -0
  253. data/lib/expressir/express/builders/subtype_constraint_builder.rb +166 -0
  254. data/lib/expressir/express/builders/syntax_builder.rb +30 -0
  255. data/lib/expressir/express/builders/type_builder.rb +238 -0
  256. data/lib/expressir/express/builders/type_decl_builder.rb +26 -0
  257. data/lib/expressir/express/builders/unique_clause_builder.rb +20 -0
  258. data/lib/expressir/express/builders/unique_rule_builder.rb +41 -0
  259. data/lib/expressir/express/builders/where_clause_builder.rb +20 -0
  260. data/lib/expressir/express/builders.rb +55 -0
  261. data/lib/expressir/express/cache.rb +43 -18
  262. data/lib/expressir/express/checker.rb +812 -0
  263. data/lib/expressir/express/concatenator.rb +79 -0
  264. data/lib/expressir/express/core.rb +95 -0
  265. data/lib/expressir/express/error.rb +124 -0
  266. data/lib/expressir/express/formatter.rb +89 -1548
  267. data/lib/expressir/express/formatters/data_types_formatter.rb +362 -0
  268. data/lib/expressir/express/formatters/declarations_formatter.rb +753 -0
  269. data/lib/expressir/express/formatters/expressions_formatter.rb +180 -0
  270. data/lib/expressir/express/formatters/literals_formatter.rb +55 -0
  271. data/lib/expressir/express/formatters/references_formatter.rb +53 -0
  272. data/lib/expressir/express/formatters/remark_formatter.rb +270 -0
  273. data/lib/expressir/express/formatters/remark_item_formatter.rb +28 -0
  274. data/lib/expressir/express/formatters/statements_formatter.rb +272 -0
  275. data/lib/expressir/express/formatters/supertype_expressions_formatter.rb +54 -0
  276. data/lib/expressir/express/formatters.rb +22 -0
  277. data/lib/expressir/express/grammar/parser.rb +712 -0
  278. data/lib/expressir/express/grammar.rb +11 -0
  279. data/lib/expressir/express/hyperlink_formatter.rb +4 -5
  280. data/lib/expressir/express/interface_dot.rb +105 -0
  281. data/lib/expressir/express/lazy_repository.rb +211 -0
  282. data/lib/expressir/express/line_map.rb +48 -0
  283. data/lib/expressir/express/listing.rb +174 -0
  284. data/lib/expressir/express/model_traversal.rb +42 -0
  285. data/lib/expressir/express/model_visitor.rb +11 -10
  286. data/lib/expressir/express/node_position_index.rb +342 -0
  287. data/lib/expressir/express/parallel_files.rb +229 -0
  288. data/lib/expressir/express/parser.rb +501 -62
  289. data/lib/expressir/express/pretty_formatter.rb +586 -0
  290. data/lib/expressir/express/pretty_gate.rb +61 -0
  291. data/lib/expressir/express/refs_overlay.rb +47 -0
  292. data/lib/expressir/express/remark_attacher.rb +1098 -0
  293. data/lib/expressir/express/remark_overlay.rb +86 -0
  294. data/lib/expressir/express/remark_scanner.rb +245 -0
  295. data/lib/expressir/express/resolve_references_model_visitor.rb +7 -9
  296. data/lib/expressir/express/schema_block_scanner.rb +137 -0
  297. data/lib/expressir/express/schema_head_formatter.rb +4 -5
  298. data/lib/expressir/express/schema_plain_source_formatter.rb +11 -0
  299. data/lib/expressir/express/schema_source_formatter.rb +15 -0
  300. data/lib/expressir/express/scope_resolver.rb +223 -0
  301. data/lib/expressir/express/self_schema_reference.rb +126 -0
  302. data/lib/expressir/express/shtolo.rb +679 -0
  303. data/lib/expressir/express/smrl_xml.rb +125 -0
  304. data/lib/expressir/express/source_formatter.rb +15 -0
  305. data/lib/expressir/express/streaming_builder.rb +435 -0
  306. data/lib/expressir/express/xsd.rb +259 -0
  307. data/lib/expressir/express.rb +53 -0
  308. data/lib/expressir/liquid.rb +1 -0
  309. data/lib/expressir/manifest/resolver.rb +210 -0
  310. data/lib/expressir/manifest/validator.rb +192 -0
  311. data/lib/expressir/manifest.rb +6 -0
  312. data/lib/expressir/mapping/refpath.rb +857 -0
  313. data/lib/expressir/mapping.rb +253 -0
  314. data/lib/expressir/model/cache.rb +10 -9
  315. data/lib/expressir/model/concerns.rb +42 -0
  316. data/lib/expressir/model/data_types/aggregate.rb +8 -13
  317. data/lib/expressir/model/data_types/array.rb +15 -21
  318. data/lib/expressir/model/data_types/bag.rb +11 -15
  319. data/lib/expressir/model/data_types/binary.rb +9 -12
  320. data/lib/expressir/model/data_types/boolean.rb +7 -2
  321. data/lib/expressir/model/data_types/enumeration.rb +11 -15
  322. data/lib/expressir/model/data_types/enumeration_item.rb +5 -7
  323. data/lib/expressir/model/data_types/generic.rb +6 -8
  324. data/lib/expressir/model/data_types/generic_entity.rb +11 -13
  325. data/lib/expressir/model/data_types/integer.rb +7 -2
  326. data/lib/expressir/model/data_types/list.rb +13 -18
  327. data/lib/expressir/model/data_types/logical.rb +7 -2
  328. data/lib/expressir/model/data_types/number.rb +7 -2
  329. data/lib/expressir/model/data_types/real.rb +7 -9
  330. data/lib/expressir/model/data_types/select.rb +13 -18
  331. data/lib/expressir/model/data_types/set.rb +11 -15
  332. data/lib/expressir/model/data_types/string.rb +9 -12
  333. data/lib/expressir/model/data_types.rb +25 -0
  334. data/lib/expressir/model/declarations/attribute.rb +19 -28
  335. data/lib/expressir/model/declarations/constant.rb +10 -16
  336. data/lib/expressir/model/declarations/derived_attribute.rb +25 -0
  337. data/lib/expressir/model/declarations/entity.rb +39 -30
  338. data/lib/expressir/model/declarations/function.rb +32 -40
  339. data/lib/expressir/model/declarations/informal_proposition_rule.rb +25 -0
  340. data/lib/expressir/model/declarations/interface.rb +25 -16
  341. data/lib/expressir/model/declarations/interface_item.rb +9 -11
  342. data/lib/expressir/model/declarations/interfaced_item.rb +15 -19
  343. data/lib/expressir/model/declarations/inverse_attribute.rb +25 -0
  344. data/lib/expressir/model/declarations/parameter.rb +10 -16
  345. data/lib/expressir/model/declarations/procedure.rb +30 -37
  346. data/lib/expressir/model/declarations/remark_item.rb +11 -11
  347. data/lib/expressir/model/declarations/rule.rb +38 -43
  348. data/lib/expressir/model/declarations/schema.rb +162 -64
  349. data/lib/expressir/model/declarations/schema_version.rb +8 -11
  350. data/lib/expressir/model/declarations/schema_version_item.rb +8 -11
  351. data/lib/expressir/model/declarations/subtype_constraint.rb +14 -22
  352. data/lib/expressir/model/declarations/type.rb +18 -18
  353. data/lib/expressir/model/declarations/unique_rule.rb +8 -13
  354. data/lib/expressir/model/declarations/variable.rb +10 -16
  355. data/lib/expressir/model/declarations/where_rule.rb +8 -13
  356. data/lib/expressir/model/declarations.rb +31 -0
  357. data/lib/expressir/model/dependency_resolver.rb +268 -0
  358. data/lib/expressir/model/exp_file.rb +42 -0
  359. data/lib/expressir/model/expressions/aggregate_initializer.rb +8 -9
  360. data/lib/expressir/model/expressions/aggregate_initializer_item.rb +10 -12
  361. data/lib/expressir/model/expressions/binary_expression.rb +42 -36
  362. data/lib/expressir/model/expressions/entity_constructor.rb +10 -12
  363. data/lib/expressir/model/expressions/function_call.rb +10 -12
  364. data/lib/expressir/model/expressions/interval.rb +18 -23
  365. data/lib/expressir/model/expressions/query_expression.rb +11 -15
  366. data/lib/expressir/model/expressions/unary_expression.rb +13 -15
  367. data/lib/expressir/model/expressions.rb +18 -0
  368. data/lib/expressir/model/identifier.rb +18 -26
  369. data/lib/expressir/model/indexes/entity_index.rb +103 -0
  370. data/lib/expressir/model/indexes/item_graph.rb +185 -0
  371. data/lib/expressir/model/indexes/reference_index.rb +148 -0
  372. data/lib/expressir/model/indexes/type_index.rb +149 -0
  373. data/lib/expressir/model/indexes.rb +12 -0
  374. data/lib/expressir/model/interface_validator.rb +384 -0
  375. data/lib/expressir/model/literals/binary.rb +7 -9
  376. data/lib/expressir/model/literals/integer.rb +7 -9
  377. data/lib/expressir/model/literals/logical.rb +10 -12
  378. data/lib/expressir/model/literals/real.rb +7 -9
  379. data/lib/expressir/model/literals/string.rb +10 -12
  380. data/lib/expressir/model/literals.rb +13 -0
  381. data/lib/expressir/model/model_element.rb +286 -117
  382. data/lib/expressir/model/references/attribute_reference.rb +9 -12
  383. data/lib/expressir/model/references/group_reference.rb +9 -12
  384. data/lib/expressir/model/references/index_reference.rb +11 -15
  385. data/lib/expressir/model/references/simple_reference.rb +11 -14
  386. data/lib/expressir/model/references.rb +12 -0
  387. data/lib/expressir/model/remark_format.rb +17 -0
  388. data/lib/expressir/model/remark_info.rb +92 -0
  389. data/lib/expressir/model/remark_placement.rb +42 -0
  390. data/lib/expressir/model/repository.rb +472 -12
  391. data/lib/expressir/model/repository_validator.rb +293 -0
  392. data/lib/expressir/model/search_engine.rb +551 -0
  393. data/lib/expressir/model/statements/alias.rb +12 -16
  394. data/lib/expressir/model/statements/assignment.rb +12 -11
  395. data/lib/expressir/model/statements/case.rb +31 -14
  396. data/lib/expressir/model/statements/case_action.rb +9 -11
  397. data/lib/expressir/model/statements/compound.rb +10 -8
  398. data/lib/expressir/model/statements/escape.rb +10 -2
  399. data/lib/expressir/model/statements/if.rb +15 -14
  400. data/lib/expressir/model/statements/null.rb +10 -2
  401. data/lib/expressir/model/statements/procedure_call.rb +11 -11
  402. data/lib/expressir/model/statements/repeat.rb +21 -28
  403. data/lib/expressir/model/statements/return.rb +9 -8
  404. data/lib/expressir/model/statements/skip.rb +10 -2
  405. data/lib/expressir/model/statements.rb +20 -0
  406. data/lib/expressir/model/supertype_expressions/binary_supertype_expression.rb +13 -17
  407. data/lib/expressir/model/supertype_expressions/oneof_supertype_expression.rb +7 -9
  408. data/lib/expressir/model/supertype_expressions.rb +12 -0
  409. data/lib/expressir/model.rb +38 -78
  410. data/lib/expressir/package/builder.rb +231 -0
  411. data/lib/expressir/package/metadata.rb +79 -0
  412. data/lib/expressir/package/reader.rb +149 -0
  413. data/lib/expressir/package.rb +8 -0
  414. data/lib/expressir/schema_manifest.rb +159 -0
  415. data/lib/expressir/schema_manifest_entry.rb +15 -0
  416. data/lib/expressir/version.rb +6 -1
  417. data/lib/expressir.rb +79 -9
  418. data/lib/tasks/verify_remarks.rake +16 -0
  419. data/rakelib/native.rake +24 -0
  420. data/rakelib/oracle.rake +52 -0
  421. data/rakelib/verify_remarks.rake +16 -0
  422. metadata +431 -129
  423. data/.cross_rubies +0 -20
  424. data/.gitmodules +0 -6
  425. data/.yardopts +0 -11
  426. data/docs/development.md +0 -90
  427. data/exe/format +0 -18
  428. data/exe/generate-parser +0 -51
  429. data/lib/expressir/cli/ui.rb +0 -36
  430. data/lib/expressir/express/2.7/express_parser.so +0 -0
  431. data/lib/expressir/express/3.0/express_parser.so +0 -0
  432. data/lib/expressir/express/3.1/express_parser.so +0 -0
  433. data/lib/expressir/express/3.2/express_parser.so +0 -0
  434. data/lib/expressir/express/visitor.rb +0 -2588
  435. data/lib/expressir/model/data_type.rb +0 -9
  436. data/lib/expressir/model/declaration.rb +0 -9
  437. data/lib/expressir/model/expression.rb +0 -9
  438. data/lib/expressir/model/literal.rb +0 -9
  439. data/lib/expressir/model/reference.rb +0 -9
  440. data/lib/expressir/model/statement.rb +0 -9
  441. data/lib/expressir/model/supertype_expression.rb +0 -9
  442. data/rakelib/antlr4-native.rake +0 -161
  443. data/rakelib/cross-ruby.rake +0 -368
  444. data/spec/acceptance/version_spec.rb +0 -27
  445. data/spec/expressir/express/cache_spec.rb +0 -89
  446. data/spec/expressir/express/formatter_spec.rb +0 -173
  447. data/spec/expressir/express/parser_spec.rb +0 -141
  448. data/spec/expressir/model/model_element_spec.rb +0 -318
  449. data/spec/spec_helper.rb +0 -24
  450. data/spec/support/console_helper.rb +0 -29
  451. data/spec/syntax/multiple.exp +0 -23
  452. data/spec/syntax/multiple.yaml +0 -198
  453. data/spec/syntax/multiple_formatted.exp +0 -71
  454. data/spec/syntax/multiple_hyperlink_formatted.exp +0 -71
  455. data/spec/syntax/multiple_schema_head_hyperlink_formatted.exp +0 -13
  456. data/spec/syntax/remark.exp +0 -193
  457. data/spec/syntax/remark.yaml +0 -471
  458. data/spec/syntax/remark_formatted.exp +0 -228
  459. data/spec/syntax/single.exp +0 -4
  460. data/spec/syntax/single.yaml +0 -18
  461. data/spec/syntax/single_formatted.exp +0 -10
  462. data/spec/syntax/single_formatted.yaml +0 -36
  463. data/spec/syntax/syntax.exp +0 -333
  464. data/spec/syntax/syntax.yaml +0 -3509
  465. data/spec/syntax/syntax_formatted.exp +0 -902
  466. data/spec/syntax/syntax_hyperlink_formatted.exp +0 -902
  467. data/spec/syntax/syntax_schema_head_formatted.exp +0 -18
@@ -0,0 +1,92 @@
1
+ module Expressir
2
+ module Model
3
+ # Represents a remark with its format and optional tag
4
+ # Supports both tail remarks (-- ...) and embedded remarks ((* ... *))
5
+ # Can include optional tags for associating remarks with specific items
6
+ class RemarkInfo < Lutaml::Model::Serializable
7
+ attribute :text, :string
8
+ attribute :format, :string, default: RemarkFormat::EMBEDDED
9
+ attribute :tag, :string # optional remark tag like "entity.attr"
10
+ # See RemarkPlacement. nil = legacy placement.
11
+ attribute :placement, :string
12
+ # Qualifies the placement. For TRAILING, which body of the owner the
13
+ # remark closes, named by that body's attribute. For INLINE,
14
+ # RemarkPlacement::OPENER_REGION when it trailed a compound statement's
15
+ # opening line rather than a whole statement.
16
+ attribute :region, :string
17
+ attribute :source_offset, :integer # byte offset in source text
18
+
19
+ # Check if this is a tail remark
20
+ # @return [Boolean] True if format is 'tail'
21
+ def tail?
22
+ format == RemarkFormat::TAIL
23
+ end
24
+
25
+ # Check if this is an embedded remark
26
+ # @return [Boolean] True if format is 'embedded'
27
+ def embedded?
28
+ format == RemarkFormat::EMBEDDED
29
+ end
30
+
31
+ # Check if this remark has a tag
32
+ # @return [Boolean] True if tag is present
33
+ def tagged?
34
+ !tag.nil? && !tag.empty?
35
+ end
36
+
37
+ # Check if this remark should be emitted above its owning statement
38
+ # @return [Boolean] True if placement is 'leading'
39
+ def leading?
40
+ placement == RemarkPlacement::LEADING
41
+ end
42
+
43
+ # Check if this remark trails its owning statement on the same line
44
+ # @return [Boolean] True if placement is 'inline'
45
+ def inline?
46
+ placement == RemarkPlacement::INLINE
47
+ end
48
+
49
+ # Check if this remark trailed the opening line of a statement spanning
50
+ # several lines, as in `IF x THEN -- why`
51
+ # @return [Boolean]
52
+ def opener?
53
+ inline? && region == RemarkPlacement::OPENER_REGION
54
+ end
55
+
56
+ # Check if this INLINE remark belongs after a mid-construct keyword of
57
+ # its owning construct — `ELSE -- why`, `OTHERWISE : -- why` — rather
58
+ # than after the statement's closing keyword.
59
+ # @param name [Symbol, String] a RemarkPlacement region constant
60
+ # @return [Boolean]
61
+ def inline_region?(name)
62
+ inline? && region == name.to_s
63
+ end
64
+
65
+ # Check if this remark closes the given body of its owning node
66
+ # @param name [Symbol, String] region attribute name
67
+ # @return [Boolean]
68
+ def trailing_region?(name)
69
+ placement == RemarkPlacement::TRAILING && region == name.to_s
70
+ end
71
+
72
+ # YAML serialization
73
+ yaml do
74
+ map "text", to: :text
75
+ map "format", to: :format
76
+ map "tag", to: :tag
77
+ map "placement", to: :placement
78
+ map "region", to: :region
79
+ end
80
+
81
+ # XML serialization
82
+ xml do
83
+ element "remark_info"
84
+ map_element "text", to: :text
85
+ map_element "format", to: :format
86
+ map_element "tag", to: :tag
87
+ map_element "placement", to: :placement
88
+ map_element "region", to: :region
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Model
5
+ # Single source of truth for where a remark sits relative to the model
6
+ # element that owns it.
7
+ #
8
+ # The parser discards comments, so attachment reconstructs their position
9
+ # from source lines. Placement records that reconstruction, letting the
10
+ # formatter put the remark back where it was written:
11
+ #
12
+ # - LEADING — on its own line(s) directly above the owning statement.
13
+ # - TRAILING — on its own line(s) at the end of a body, before the closing
14
+ # keyword. The owner is the body's owner, and RemarkInfo#region names
15
+ # which body: an IF owns two, and they close at different keywords.
16
+ # - INLINE — on the same line as the owning statement, after its text.
17
+ # Emitted after the whole statement, which for a single-line one is the
18
+ # line it was written on. RemarkInfo#region separates the other case:
19
+ # OPENER_REGION means the remark trailed the opening line of a statement
20
+ # spanning several lines, as in `IF x THEN -- why`, and belongs back on
21
+ # that opener rather than after the closing keyword.
22
+ #
23
+ # `nil` means the remark was attached by a legacy path, or predates
24
+ # placement tracking. Those keep their historical emission and must not
25
+ # be rendered by placement-aware emitters.
26
+ module RemarkPlacement
27
+ LEADING = "leading"
28
+ TRAILING = "trailing"
29
+ INLINE = "inline"
30
+
31
+ # Region of an INLINE remark that trailed a compound statement's opener.
32
+ OPENER_REGION = "opener"
33
+
34
+ # Regions of INLINE remarks that trailed a mid-construct keyword line —
35
+ # `ELSE -- why` or `OTHERWISE : -- why`. The owning construct is the
36
+ # enclosing IF / CASE, and the remark belongs back after that keyword,
37
+ # not after the construct's closing END_.
38
+ ELSE_REGION = "else"
39
+ OTHERWISE_REGION = "otherwise"
40
+ end
41
+ end
42
+ end
@@ -1,23 +1,483 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Expressir
2
4
  module Model
3
- # Multi-schema global scope
5
+ # Multi-schema global scope with enhanced repository features
6
+ # Focuses on schema management and delegates indexing/validation to specialized classes
7
+ #
8
+ # A Repository contains multiple ExpFile instances (one per parsed .exp file).
9
+ #
10
+ # Structure:
11
+ # Repository
12
+ # └── files: [ExpFile, ...]
13
+ # └── ExpFile (path: "a.exp")
14
+ # ├── untagged_remarks: [...] # file-level preamble
15
+ # └── schemas: [SchemaA]
4
16
  class Repository < ModelElement
5
- model_attr_accessor :schemas, 'Array<Declarations::Schema>'
17
+ # Internal storage for schemas (used for direct manipulation)
18
+ attribute :files, ExpFile, collection: true, initialize_empty: true
19
+ attribute :_class, :string, default: -> { self.class.name }
20
+
21
+ # Base directory for schema files
22
+ attr_accessor :base_dir
23
+
24
+ # Index instances (lazy-loaded)
25
+ attr_reader :entity_index, :type_index, :reference_index
26
+
27
+ # Item-level graph; loaded from the compiled-set artifact on
28
+ # warm starts, built on demand otherwise.
29
+ attr_accessor :item_graph
30
+
31
+ # Restore deserialized indexes (used by Package::Reader)
32
+ def restore_indexes(entity_index: nil, type_index: nil,
33
+ reference_index: nil)
34
+ @entity_index = entity_index if entity_index
35
+ @type_index = type_index if type_index
36
+ @reference_index = reference_index if reference_index
37
+ end
38
+
39
+ # Internal schema storage for direct manipulation
40
+ attr_reader :_schemas
6
41
 
7
- # @param [Hash] options
8
- # @option options [Array<Declarations::Schema>] :schemas
9
- def initialize(options = {})
10
- @schemas = options[:schemas] || []
42
+ key_value do
43
+ map "_class", to: :_class, render_default: true
44
+ map "files", to: :files
45
+ end
46
+
47
+ liquid do
48
+ map :schemas, to: :schemas
49
+ end
50
+
51
+ def initialize(*, base_dir: nil, schemas: nil, **)
52
+ super(*, **)
53
+ @base_dir = base_dir
54
+ @entity_index = nil
55
+ @type_index = nil
56
+ @reference_index = nil
57
+ @_schemas = []
58
+
59
+ # Support direct schemas initialization
60
+ schemas&.each { |schema| @_schemas << schema }
61
+ end
11
62
 
12
- super
63
+ # Get all schemas (from both files and direct storage).
64
+ # Files that failed to parse are nil in `files` — a parse failure must
65
+ # not crash schema enumeration with a NoMethodError from in here.
66
+ # @return [Array<Declarations::Schema>]
67
+ def schemas
68
+ file_schemas = files.compact.flat_map(&:schemas).compact
69
+ file_schemas + @_schemas
13
70
  end
14
71
 
15
- # @return [Array<Declaration>]
72
+ # Alias for schemas
73
+ # @return [Array<Declarations::Schema>]
74
+ def all_schemas
75
+ schemas
76
+ end
77
+
78
+ # Add a schema to the repository
79
+ # @param schema [Declarations::Schema] Schema to add
80
+ def add_schema(schema)
81
+ return unless schema
82
+
83
+ @_schemas << schema
84
+ end
85
+
86
+ # @return [Array<Declarations::Schema>]
16
87
  def children
17
- [
18
- *schemas
19
- ]
88
+ schemas
89
+ end
90
+
91
+ # Build indexes for entities, types, and references
92
+ # @return [void]
93
+ def build_indexes
94
+ target_schemas = all_schemas
95
+ @entity_index = Indexes::EntityIndex.new(target_schemas)
96
+ @type_index = Indexes::TypeIndex.new(target_schemas)
97
+ @reference_index = Indexes::ReferenceIndex.new(target_schemas)
98
+ end
99
+
100
+ # Find entity by qualified name
101
+ # @param qualified_name [String] Entity qualified name (e.g., "action_schema.action")
102
+ # @return [Declarations::Entity, nil] Found entity or nil
103
+ def find_entity(qualified_name:)
104
+ ensure_indexes_built
105
+ @entity_index.find(qualified_name)
106
+ end
107
+
108
+ # Find type by qualified name
109
+ # @param qualified_name [String] Type qualified name
110
+ # @return [Declarations::Type, nil] Found type or nil
111
+ def find_type(qualified_name:)
112
+ ensure_indexes_built
113
+ @type_index.find(qualified_name)
114
+ end
115
+
116
+ # List all entities
117
+ # @param schema [String, nil] Filter by schema name
118
+ # @param format [Symbol] Output format (:object, :hash, :json, :yaml)
119
+ # @return [Array] List of entities
120
+ def list_entities(schema: nil, format: :object)
121
+ ensure_indexes_built
122
+
123
+ entities = @entity_index.list(schema: schema)
124
+
125
+ format_output(entities, format) do |entity|
126
+ { id: entity.id, schema: entity.parent.id, path: entity.path }
127
+ end
128
+ end
129
+
130
+ # List all types
131
+ # @param schema [String, nil] Filter by schema name
132
+ # @param category [String, nil] Filter by type category (select, enumeration, etc.)
133
+ # @param format [Symbol] Output format (:object, :hash, :json, :yaml)
134
+ # @return [Array] List of types
135
+ def list_types(schema: nil, category: nil, format: :object)
136
+ ensure_indexes_built
137
+
138
+ types = @type_index.list(schema: schema, category: category)
139
+
140
+ format_output(types, format) do |type|
141
+ { id: type.id, schema: type.parent.id, path: type.path,
142
+ category: @type_index.categorize(type) }
143
+ end
144
+ end
145
+
146
+ # Resolve all references across schemas
147
+ # Uses the existing ResolveReferencesModelVisitor
148
+ # @return [void]
149
+ def resolve_all_references
150
+ visitor = Expressir::Express::ResolveReferencesModelVisitor.new
151
+ visitor.visit(self)
152
+ end
153
+
154
+ # Validate repository consistency
155
+ # @param strict [Boolean] Enable strict validation
156
+ # @return [Hash] Validation results with :valid?, :errors, :warnings
157
+ def validate(strict: false)
158
+ ensure_indexes_built
159
+ validator = RepositoryValidator.new(all_schemas, @reference_index)
160
+ validator.validate(strict: strict)
161
+ end
162
+
163
+ # Get statistics
164
+ # @param format [Symbol] Output format (:hash, :json, :yaml)
165
+ # @return [Hash, String] Repository statistics
166
+ def statistics(format: :hash)
167
+ ensure_indexes_built
168
+
169
+ stats = {
170
+ total_schemas: all_schemas.size,
171
+ total_entities: count_entities,
172
+ total_types: count_types,
173
+ total_functions: count_functions,
174
+ total_rules: count_rules,
175
+ total_procedures: count_procedures,
176
+ entities_by_schema: entities_by_schema_counts,
177
+ types_by_category: types_by_category_counts,
178
+ interfaces: interface_counts,
179
+ }
180
+
181
+ case format
182
+ when :json
183
+ require "json"
184
+ stats.to_json
185
+ when :yaml
186
+ require "yaml"
187
+ stats.to_yaml
188
+ else
189
+ stats
190
+ end
191
+ end
192
+
193
+ # Group schemas by category based on their contents
194
+ # @return [Hash] Hash with category keys and schema arrays
195
+ def schemas_by_category
196
+ target_schemas = all_schemas
197
+ {
198
+ with_entities: target_schemas.select { |s| s.entities&.any? },
199
+ with_types: target_schemas.select { |s| s.types&.any? },
200
+ with_functions: target_schemas.select { |s| s.functions&.any? },
201
+ with_rules: target_schemas.select { |s| s.rules&.any? },
202
+ interface_only: target_schemas.select do |s|
203
+ s.interfaces&.any? && !s.entities&.any? && !s.types&.any?
204
+ end,
205
+ empty: target_schemas.select do |s|
206
+ !s.entities&.any? && !s.types&.any? && !s.functions&.any?
207
+ end,
208
+ }
209
+ end
210
+
211
+ # Get largest schemas by total element count
212
+ # @param limit [Integer] Maximum number of schemas to return
213
+ # @return [Array<Hash>] Array of hashes with :schema and :total_elements
214
+ def largest_schemas(limit = 10)
215
+ all_schemas.map do |s|
216
+ {
217
+ schema: s,
218
+ total_elements: count_schema_elements(s),
219
+ }
220
+ end.sort_by { |item| -item[:total_elements] }.take(limit)
221
+ end
222
+
223
+ # Calculate schema complexity score
224
+ # Entities=2, Types=1, Functions=3, Procedures=3, Rules=4, Interfaces=2
225
+ # @param schema [Declarations::Schema] Schema to analyze
226
+ # @return [Integer] Complexity score
227
+ def schema_complexity(schema)
228
+ score = 0
229
+ score += (schema.entities&.size || 0) * 2
230
+ score += (schema.types&.size || 0) * 1
231
+ score += (schema.functions&.size || 0) * 3
232
+ score += (schema.procedures&.size || 0) * 3
233
+ score += (schema.rules&.size || 0) * 4
234
+ score += (schema.interfaces&.size || 0) * 2
235
+ score
236
+ end
237
+
238
+ # Get schemas sorted by complexity
239
+ # @param limit [Integer] Maximum number of schemas to return
240
+ # @return [Array<Hash>] Array of hashes with :schema and :complexity
241
+ def schemas_by_complexity(limit = 10)
242
+ all_schemas.map { |s| { schema: s, complexity: schema_complexity(s) } }
243
+ .sort_by { |item| -item[:complexity] }
244
+ .take(limit)
245
+ end
246
+
247
+ # Get dependency statistics
248
+ # @return [Hash] Statistics about interface dependencies
249
+ def dependency_statistics
250
+ stats = {
251
+ total_interfaces: 0,
252
+ use_from_count: 0,
253
+ reference_from_count: 0,
254
+ most_referenced: [],
255
+ most_dependent: [],
256
+ }
257
+
258
+ reference_counts = Hash.new(0)
259
+ dependency_counts = Hash.new(0)
260
+
261
+ all_schemas.each do |schema|
262
+ next unless schema.interfaces&.any?
263
+
264
+ stats[:total_interfaces] += schema.interfaces.size
265
+ dependency_counts[schema.id] = schema.interfaces.size
266
+
267
+ schema.interfaces.each do |interface|
268
+ stats[:use_from_count] += 1 if interface.kind == Declarations::Interface::USE
269
+ stats[:reference_from_count] += 1 if interface.kind == Declarations::Interface::REFERENCE
270
+ reference_counts[interface.schema.id] += 1 if interface.schema
271
+ end
272
+ end
273
+
274
+ stats[:most_referenced] = reference_counts.sort_by do |_, v|
275
+ -v
276
+ end.take(10).to_h
277
+ stats[:most_dependent] = dependency_counts.sort_by do |_, v|
278
+ -v
279
+ end.take(10).to_h
280
+
281
+ stats
282
+ end
283
+
284
+ # Generate SchemaManifest from repository
285
+ # @return [SchemaManifest] Manifest describing all schemas
286
+ def to_manifest
287
+ manifest = Expressir::SchemaManifest.new
288
+ all_schemas.each do |schema|
289
+ manifest.schemas << Expressir::SchemaManifestEntry.new(
290
+ id: schema.id,
291
+ path: schema.file || "#{schema.id}.exp",
292
+ )
293
+ end
294
+ manifest
295
+ end
296
+
297
+ # Build repository from list of schema files
298
+ # @param file_paths [Array<String>] Schema file paths
299
+ # @param base_dir [String, nil] Base directory for path resolution
300
+ # @param max_processes [Integer, nil] parse in a fork worker pool when
301
+ # set above 1 on a fork-capable platform (advisory; degrades to
302
+ # sequential otherwise). Unlike Express::Parser.from_files, a file
303
+ # that fails to parse always raises.
304
+ # @return [Repository] Built repository with all schemas
305
+ def self.from_files(file_paths, base_dir: nil, max_processes: nil)
306
+ repo = new(base_dir: base_dir)
307
+
308
+ pool = Expressir::Express::ParallelFiles
309
+ parsed_files = if pool.sequential?(file_paths, max_processes)
310
+ file_paths.map do |path|
311
+ Expressir::Express::Parser.from_file(path)
312
+ end
313
+ else
314
+ pool.run(file_paths,
315
+ parse: ->(path) { Expressir::Express::Parser.from_file(path) },
316
+ max_processes: max_processes,
317
+ strict: true)
318
+ end
319
+
320
+ parsed_files.each do |parsed|
321
+ repo.files << parsed if parsed.is_a?(ExpFile)
322
+ end
323
+
324
+ repo.resolve_all_references
325
+ repo
326
+ end
327
+
328
+ # Load repository from LER package
329
+ # @param package_path [String] Path to .ler package file
330
+ # @return [Repository] Loaded repository
331
+ def self.from_package(package_path)
332
+ Package::Reader.load(package_path)
333
+ end
334
+
335
+ # Export repository to LER package
336
+ # @param output_path [String] Path for output .ler file
337
+ # @param options [Hash] Package options
338
+ # @option options [String] :name Package name
339
+ # @option options [String] :version Package version
340
+ # @option options [String] :description Package description
341
+ # @option options [String] :express_mode ('include_all') Bundling mode
342
+ # @option options [String] :resolution_mode ('resolved') Resolution mode
343
+ # @option options [String] :serialization_format ('marshal') Serialization format
344
+ # @return [String] Path to created package
345
+ def export_to_package(output_path, options = {})
346
+ builder = Package::Builder.new
347
+ builder.build(self, output_path, options)
348
+ end
349
+
350
+ private
351
+
352
+ # Count total elements in schema
353
+ # @param schema [Declarations::Schema] Schema to count elements from
354
+ # @return [Integer] Total count of all elements
355
+ def count_schema_elements(schema)
356
+ (schema.entities&.size || 0) +
357
+ (schema.types&.size || 0) +
358
+ (schema.functions&.size || 0) +
359
+ (schema.procedures&.size || 0) +
360
+ (schema.rules&.size || 0) +
361
+ (schema.constants&.size || 0)
362
+ end
363
+
364
+ # Ensure indexes are built before use
365
+ # @return [void]
366
+ def ensure_indexes_built
367
+ build_indexes if @entity_index.nil? || @entity_index.empty?
368
+ end
369
+
370
+ # Format output based on requested format
371
+ # @param items [Array] Items to format
372
+ # @param format [Symbol] Output format
373
+ # @yield [item] Block to convert item to hash
374
+ # @return [Array, String] Formatted output
375
+ def format_output(items, format, &)
376
+ case format
377
+ when :hash
378
+ items.map(&)
379
+ when :json
380
+ require "json"
381
+ items.map(&).to_json
382
+ when :yaml
383
+ require "yaml"
384
+ items.map(&).to_yaml
385
+ else
386
+ items
387
+ end
388
+ end
389
+
390
+ # Count entities by schema
391
+ # @return [Hash<String, Integer>] Entity counts per schema
392
+ def entities_by_schema_counts
393
+ counts = {}
394
+ all_schemas.each do |schema|
395
+ counts[schema.id] = schema.entities&.size || 0
396
+ end
397
+ counts
398
+ end
399
+
400
+ # Count types by category
401
+ # @return [Hash<Symbol, Integer>] Type counts per category
402
+ def types_by_category_counts
403
+ counts = {
404
+ select: 0,
405
+ enumeration: 0,
406
+ aggregate: 0,
407
+ defined: 0,
408
+ }
409
+
410
+ all_schemas.each do |schema|
411
+ next unless schema.types
412
+
413
+ schema.types.each do |type|
414
+ category = @type_index.categorize(type).to_sym
415
+ counts[category] ||= 0
416
+ counts[category] += 1
417
+ end
418
+ end
419
+
420
+ counts
421
+ end
422
+
423
+ # Count interfaces by type
424
+ # @return [Hash<Symbol, Integer>] Interface counts
425
+ def interface_counts
426
+ counts = {
427
+ use_from: 0,
428
+ reference_from: 0,
429
+ }
430
+
431
+ all_schemas.each do |schema|
432
+ next unless schema.interfaces
433
+
434
+ schema.interfaces.each do |interface|
435
+ if interface.kind == Declarations::Interface::USE
436
+ counts[:use_from] += 1
437
+ elsif interface.kind == Declarations::Interface::REFERENCE
438
+ counts[:reference_from] += 1
439
+ end
440
+ end
441
+ end
442
+
443
+ counts
444
+ end
445
+
446
+ # Count total entities across all schemas
447
+ # Uses indexes if available, falls back to schemas collection
448
+ # @return [Integer] Total entity count
449
+ def count_entities
450
+ return @entity_index.count if @entity_index && !@entity_index.empty?
451
+
452
+ all_schemas.sum { |schema| schema.entities&.size || 0 }
453
+ end
454
+
455
+ # Count total types across all schemas
456
+ # Uses indexes if available, falls back to schemas collection
457
+ # @return [Integer] Total type count
458
+ def count_types
459
+ return @type_index.count if @type_index && !@type_index.empty?
460
+
461
+ all_schemas.sum { |schema| schema.types&.size || 0 }
462
+ end
463
+
464
+ # Count total functions across all schemas
465
+ # @return [Integer] Total function count
466
+ def count_functions
467
+ all_schemas.sum { |schema| schema.functions&.size || 0 }
468
+ end
469
+
470
+ # Count total rules across all schemas
471
+ # @return [Integer] Total rule count
472
+ def count_rules
473
+ all_schemas.sum { |schema| schema.rules&.size || 0 }
474
+ end
475
+
476
+ # Count total procedures across all schemas
477
+ # @return [Integer] Total procedure count
478
+ def count_procedures
479
+ all_schemas.sum { |schema| schema.procedures&.size || 0 }
20
480
  end
21
481
  end
22
482
  end
23
- end
483
+ end