expressir 1.2.10-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,231 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zip"
4
+ require "time"
5
+
6
+ module Expressir
7
+ module Package
8
+ # Builds LER packages from Repository instances
9
+ # Single responsibility: Create .ler ZIP packages
10
+ class Builder
11
+ # Build LER package from repository
12
+ # @param repository [Model::Repository] Repository to package
13
+ # @param output_path [String] Output .ler file path
14
+ # @param options [Hash] Package options
15
+ # @option options [String] :name Package name
16
+ # @option options [String] :version Package version
17
+ # @option options [String] :description Package description
18
+ # @option options [String] :express_mode ('include_all') Bundling mode
19
+ # @option options [String] :resolution_mode ('resolved') Resolution mode
20
+ # @option options [String] :serialization_format ('marshal') Serialization format
21
+ # @return [String] Path to created package
22
+ def build(repository, output_path, options = {})
23
+ options = normalize_options(options)
24
+ metadata = build_metadata(repository, options)
25
+
26
+ # Validate metadata
27
+ validation = metadata.validate
28
+ unless validation[:valid?]
29
+ raise ArgumentError,
30
+ "Invalid metadata: #{validation[:errors].join(', ')}"
31
+ end
32
+
33
+ # Create ZIP package
34
+ Zip::File.open(output_path, create: true) do |zip|
35
+ add_metadata(zip, metadata)
36
+ add_schemas(zip, repository, options)
37
+ add_indexes(zip, repository)
38
+ add_manifest(zip, repository)
39
+ end
40
+
41
+ output_path
42
+ end
43
+
44
+ private
45
+
46
+ # Normalize options with defaults
47
+ # @param options [Hash] Raw options
48
+ # @return [Hash] Normalized options
49
+ def normalize_options(options)
50
+ {
51
+ name: options[:name] || "Unnamed Package",
52
+ version: options[:version] || "1.0.0",
53
+ description: options[:description] || "",
54
+ express_mode: options[:express_mode] || "include_all",
55
+ resolution_mode: options[:resolution_mode] || "resolved",
56
+ serialization_format: options[:serialization_format] || "marshal",
57
+ }
58
+ end
59
+
60
+ # Build metadata from repository and options
61
+ # @param repository [Model::Repository] Repository instance
62
+ # @param options [Hash] Package options
63
+ # @return [Metadata] Package metadata
64
+ def build_metadata(repository, options)
65
+ Metadata.new(
66
+ name: options[:name],
67
+ version: options[:version],
68
+ description: options[:description],
69
+ created_at: Time.now.utc.iso8601,
70
+ created_by: "expressir",
71
+ expressir_version: Expressir::Version::VERSION,
72
+ express_mode: options[:express_mode],
73
+ resolution_mode: options[:resolution_mode],
74
+ serialization_format: options[:serialization_format],
75
+ files: count_files(repository),
76
+ schemas: repository.schemas.size,
77
+ )
78
+ end
79
+
80
+ # Count files in repository
81
+ # @param repository [Model::Repository] Repository instance
82
+ # @return [Integer] File count
83
+ def count_files(repository)
84
+ repository.schemas.count(&:file)
85
+ end
86
+
87
+ # Add metadata to package
88
+ # @param zip [Zip::File] ZIP archive
89
+ # @param metadata [Metadata] Package metadata
90
+ # @return [void]
91
+ def add_metadata(zip, metadata)
92
+ zip.get_output_stream("metadata.yaml") do |stream|
93
+ stream.write(metadata.to_yaml)
94
+ end
95
+ end
96
+
97
+ # Add schemas to package based on resolution mode
98
+ # @param zip [Zip::File] ZIP archive
99
+ # @param repository [Model::Repository] Repository instance
100
+ # @param options [Hash] Package options
101
+ # @return [void]
102
+ def add_schemas(zip, repository, options)
103
+ case options[:resolution_mode]
104
+ when "resolved"
105
+ add_serialized_repository(zip, repository,
106
+ options[:serialization_format])
107
+ end
108
+
109
+ # Add EXPRESS files if include_all mode
110
+ if options[:express_mode] == "include_all"
111
+ add_express_files(zip, repository)
112
+ end
113
+ end
114
+
115
+ # Add serialized repository to package
116
+ # @param zip [Zip::File] ZIP archive
117
+ # @param repository [Model::Repository] Repository instance
118
+ # @param format [String] Serialization format
119
+ # @return [void]
120
+ def add_serialized_repository(zip, repository, format)
121
+ # Normalize repository - ensure all schemas are in files for serialization
122
+ normalized_repo = normalize_repository(repository)
123
+
124
+ case format
125
+ when "marshal"
126
+ zip.get_output_stream("repository.marshal") do |stream|
127
+ stream.write(Marshal.dump(normalized_repo))
128
+ end
129
+ when "json"
130
+ zip.get_output_stream("repository.json") do |stream|
131
+ stream.write(normalized_repo.to_json)
132
+ end
133
+ when "yaml"
134
+ zip.get_output_stream("repository.yaml") do |stream|
135
+ stream.write(normalized_repo.to_yaml)
136
+ end
137
+ end
138
+ end
139
+
140
+ # Normalize repository for serialization
141
+ # Ensures all schemas are in files (not in @_schemas)
142
+ # @param repository [Model::Repository] Repository to normalize
143
+ # @return [Model::Repository] Normalized repository
144
+ def normalize_repository(repository)
145
+ # Create a new repository with proper file structure
146
+ normalized = Model::Repository.new(base_dir: repository.base_dir)
147
+
148
+ # Copy existing files
149
+ repository.files&.each do |file|
150
+ normalized.files << file
151
+ end
152
+
153
+ # Get schemas that are not already in files
154
+ file_schema_ids = normalized.files.flat_map(&:schemas).compact.map(&:id)
155
+ direct_schemas = repository.schemas.reject do |s|
156
+ file_schema_ids.include?(s.id)
157
+ end
158
+
159
+ # Create an ExpFile for direct schemas
160
+ if direct_schemas.any?
161
+ exp_file = Model::ExpFile.new(path: "direct_schemas.exp")
162
+ exp_file.schemas = direct_schemas
163
+ normalized.files << exp_file
164
+ end
165
+
166
+ normalized
167
+ end
168
+
169
+ # Add EXPRESS files to package
170
+ # @param zip [Zip::File] ZIP archive
171
+ # @param repository [Model::Repository] Repository instance
172
+ # @return [void]
173
+ def add_express_files(zip, repository)
174
+ repository.schemas.each do |schema|
175
+ next unless schema.file && File.exist?(schema.file)
176
+
177
+ # Use schema id as filename
178
+ filename = "express_files/#{schema.id}.exp"
179
+ zip.get_output_stream(filename) do |stream|
180
+ stream.write(File.read(schema.file))
181
+ end
182
+ end
183
+ end
184
+
185
+ # Add indexes to package
186
+ # @param zip [Zip::File] ZIP archive
187
+ # @param repository [Model::Repository] Repository instance
188
+ # @return [void]
189
+ def add_indexes(zip, repository)
190
+ # Ensure indexes are built
191
+ repository.build_indexes if repository.entity_index.nil?
192
+
193
+ # Serialize indexes using Marshal for performance
194
+ zip.get_output_stream("entity_index.marshal") do |stream|
195
+ stream.write(Marshal.dump(repository.entity_index))
196
+ end
197
+
198
+ zip.get_output_stream("type_index.marshal") do |stream|
199
+ stream.write(Marshal.dump(repository.type_index))
200
+ end
201
+
202
+ zip.get_output_stream("reference_index.marshal") do |stream|
203
+ stream.write(Marshal.dump(repository.reference_index))
204
+ end
205
+ end
206
+
207
+ # Add manifest to package with rewritten paths
208
+ # @param zip [Zip::File] ZIP archive
209
+ # @param repository [Model::Repository] Repository instance
210
+ # @return [void]
211
+ def add_manifest(zip, repository)
212
+ # Create manifest with package-internal paths
213
+ manifest = Expressir::SchemaManifest.new
214
+
215
+ repository.schemas.each do |schema|
216
+ manifest.schemas << Expressir::SchemaManifestEntry.new(
217
+ id: schema.id,
218
+ path: "express_files/#{schema.id}.exp", # Package-internal path
219
+ )
220
+ end
221
+
222
+ # Set output_path to suppress relative path calculation
223
+ manifest.output_path = "manifest.yaml"
224
+
225
+ zip.get_output_stream("manifest.yaml") do |stream|
226
+ stream.write(manifest.to_yaml)
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Package
5
+ # Package metadata with serialization support
6
+ # Stores configuration and statistics for LER packages
7
+ class Metadata < Lutaml::Model::Serializable
8
+ attribute :name, :string
9
+ attribute :version, :string
10
+ attribute :description, :string
11
+ attribute :created_at, :string
12
+ attribute :created_by, :string, default: -> { "expressir" }
13
+ attribute :expressir_version, :string
14
+ attribute :express_mode, :string, default: -> { "include_all" }
15
+ attribute :resolution_mode, :string, default: -> { "resolved" }
16
+ attribute :serialization_format, :string, default: -> { "marshal" }
17
+ attribute :files, :integer
18
+ attribute :schemas, :integer
19
+
20
+ yaml do
21
+ map "name", to: :name
22
+ map "version", to: :version
23
+ map "description", to: :description
24
+ map "created_at", to: :created_at
25
+ map "created_by", to: :created_by
26
+ map "expressir_version", to: :expressir_version
27
+ map "express_mode", to: :express_mode
28
+ map "resolution_mode", to: :resolution_mode
29
+ map "serialization_format", to: :serialization_format
30
+ map "files", to: :files
31
+ map "schemas", to: :schemas
32
+ end
33
+
34
+ # Validate metadata configuration
35
+ # @return [Hash] Validation result with :valid? and :errors
36
+ def validate
37
+ errors = []
38
+
39
+ errors << "name is required" if name.nil? || name.empty?
40
+ errors << "version is required" if version.nil? || version.empty?
41
+
42
+ unless %w[include_all allow_external].include?(express_mode)
43
+ errors << "express_mode must be 'include_all' or 'allow_external'"
44
+ end
45
+
46
+ unless %w[resolved bare].include?(resolution_mode)
47
+ errors << "resolution_mode must be 'resolved' or 'bare'"
48
+ end
49
+
50
+ unless %w[marshal json yaml].include?(serialization_format)
51
+ errors << "serialization_format must be 'marshal', 'json', or 'yaml'"
52
+ end
53
+
54
+ {
55
+ valid?: errors.empty?,
56
+ errors: errors,
57
+ }
58
+ end
59
+
60
+ # Convert metadata to hash
61
+ # @return [Hash] Metadata as hash
62
+ def to_h
63
+ {
64
+ "name" => name,
65
+ "version" => version,
66
+ "description" => description,
67
+ "created_at" => created_at,
68
+ "created_by" => created_by,
69
+ "expressir_version" => expressir_version,
70
+ "express_mode" => express_mode,
71
+ "resolution_mode" => resolution_mode,
72
+ "serialization_format" => serialization_format,
73
+ "files" => files,
74
+ "schemas" => schemas,
75
+ }
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zip"
4
+
5
+ module Expressir
6
+ module Package
7
+ # Loads LER packages into Repository instances
8
+ # Single responsibility: Load .ler ZIP packages
9
+ class Reader
10
+ # Load repository from LER package
11
+ # @param package_path [String] Path to .ler file
12
+ # @return [Model::Repository] Loaded repository
13
+ def self.load(package_path)
14
+ new.load(package_path)
15
+ end
16
+
17
+ # Load repository from LER package
18
+ # @param package_path [String] Path to .ler file
19
+ # @return [Model::Repository] Loaded repository
20
+ def load(package_path)
21
+ unless File.exist?(package_path)
22
+ raise ArgumentError, "Package file not found: #{package_path}"
23
+ end
24
+
25
+ repository = nil
26
+ metadata = nil
27
+
28
+ Zip::File.open(package_path) do |zip|
29
+ # Read metadata first
30
+ metadata = load_metadata(zip)
31
+
32
+ # Load repository based on resolution mode
33
+ repository = if metadata.resolution_mode == "resolved"
34
+ load_serialized_repository(zip,
35
+ metadata.serialization_format)
36
+ else
37
+ load_from_express_files(zip)
38
+ end
39
+
40
+ # Load and restore indexes
41
+ load_indexes(zip, repository)
42
+ end
43
+
44
+ repository
45
+ end
46
+
47
+ private
48
+
49
+ # Load metadata from package
50
+ # @param zip [Zip::File] ZIP archive
51
+ # @return [Metadata] Package metadata
52
+ def load_metadata(zip)
53
+ entry = zip.find_entry("metadata.yaml")
54
+ raise "Metadata not found in package" unless entry
55
+
56
+ Metadata.from_yaml(entry.get_input_stream.read)
57
+ end
58
+
59
+ # Load serialized repository from package
60
+ # @param zip [Zip::File] ZIP archive
61
+ # @param format [String] Serialization format
62
+ # @return [Model::Repository] Repository instance
63
+ def load_serialized_repository(zip, format)
64
+ case format
65
+ when "marshal"
66
+ load_marshal_repository(zip)
67
+ when "json"
68
+ load_json_repository(zip)
69
+ when "yaml"
70
+ load_yaml_repository(zip)
71
+ else
72
+ raise "Unknown serialization format: #{format}"
73
+ end
74
+ end
75
+
76
+ # Load repository from Marshal format
77
+ # @param zip [Zip::File] ZIP archive
78
+ # @return [Model::Repository] Repository instance
79
+ def load_marshal_repository(zip)
80
+ entry = zip.find_entry("repository.marshal")
81
+ raise "Serialized repository not found" unless entry
82
+
83
+ Marshal.load(entry.get_input_stream.read)
84
+ end
85
+
86
+ # Load repository from JSON format
87
+ # @param zip [Zip::File] ZIP archive
88
+ # @return [Model::Repository] Repository instance
89
+ def load_json_repository(zip)
90
+ entry = zip.find_entry("repository.json")
91
+ raise "Serialized repository not found" unless entry
92
+
93
+ Model::Repository.from_json(entry.get_input_stream.read)
94
+ end
95
+
96
+ # Load repository from YAML format
97
+ # @param zip [Zip::File] ZIP archive
98
+ # @return [Model::Repository] Repository instance
99
+ def load_yaml_repository(zip)
100
+ entry = zip.find_entry("repository.yaml")
101
+ raise "Serialized repository not found" unless entry
102
+
103
+ Model::Repository.from_yaml(entry.get_input_stream.read)
104
+ end
105
+
106
+ # Load repository from EXPRESS files
107
+ # @param zip [Zip::File] ZIP archive
108
+ # @return [Model::Repository] Repository instance
109
+ def load_from_express_files(zip)
110
+ repository = Model::Repository.new
111
+
112
+ # Find all EXPRESS files in the package
113
+ express_entries = zip.entries.select do |entry|
114
+ entry.name.start_with?("express_files/") && entry.name.end_with?(".exp")
115
+ end
116
+
117
+ # Parse each EXPRESS file
118
+ express_entries.each do |entry|
119
+ content = entry.get_input_stream.read
120
+ schema = Expressir::Express::Parser.from_exp(content)
121
+ repository.schemas << schema.schemas.first if schema.schemas.any?
122
+ end
123
+
124
+ # Resolve references
125
+ repository.resolve_all_references
126
+
127
+ repository
128
+ end
129
+
130
+ # Load and restore indexes
131
+ # @param zip [Zip::File] ZIP archive
132
+ # @param repository [Model::Repository] Repository instance
133
+ # @return [void]
134
+ def load_indexes(zip, repository)
135
+ indexes = {}
136
+
137
+ %w[entity_index type_index reference_index].each do |name|
138
+ entry = zip.find_entry("#{name}.marshal")
139
+ if entry
140
+ indexes[name.to_sym] =
141
+ Marshal.load(entry.get_input_stream.read)
142
+ end
143
+ end
144
+
145
+ repository.restore_indexes(**indexes) unless indexes.empty?
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,8 @@
1
+ # lib/expressir/package.rb
2
+ module Expressir
3
+ module Package
4
+ autoload :Metadata, "#{__dir__}/package/metadata"
5
+ autoload :Builder, "#{__dir__}/package/builder"
6
+ autoload :Reader, "#{__dir__}/package/reader"
7
+ end
8
+ end
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ class SchemaManifest < Lutaml::Model::Serializable
5
+ attribute :schemas, "Expressir::SchemaManifestEntry",
6
+ collection: true,
7
+ initialize_empty: true
8
+ attribute :path, :string
9
+ attr_accessor :output_path
10
+
11
+ def initialize(**args)
12
+ @path = path_relative_to_absolute(path) if path
13
+ super
14
+ end
15
+
16
+ def base_path
17
+ File.dirname(@path)
18
+ end
19
+
20
+ yaml do
21
+ map "schemas", with: { from: :schemas_from_yaml, to: :schemas_to_yaml }
22
+ end
23
+
24
+ def self.from_file(path)
25
+ from_yaml(File.read(path)).tap do |x|
26
+ x.set_initial_path(path)
27
+ end
28
+ rescue StandardError => e
29
+ raise ManifestValidationError,
30
+ "Invalid schema manifest format: #{e.message}"
31
+ end
32
+
33
+ def to_file(to_path = path)
34
+ FileUtils.mkdir_p(File.dirname(to_path))
35
+ File.write(to_path, to_yaml)
36
+ end
37
+
38
+ def set_initial_path(new_path)
39
+ @path = path_relative_to_absolute(new_path)
40
+ schemas.each do |schema|
41
+ schema.path = path_relative_to_absolute(schema.path)
42
+ schema.container_path = File.expand_path(@path)
43
+ end
44
+ end
45
+
46
+ def schemas_from_yaml(model, value)
47
+ model.schemas = value.map do |k, v|
48
+ SchemaManifestEntry.new(id: k,
49
+ path: path_relative_to_absolute(v["path"]))
50
+ end
51
+ end
52
+
53
+ def schemas_to_yaml(model, doc)
54
+ doc["schemas"] = model.schemas.sort_by(&:id).to_h do |schema|
55
+ # We are outputting the schemas collection file to the directory where
56
+ # the collection config is at (assumed to be Dir.pwd), not to the
57
+ # directory we sourced the manifest from, e.g.
58
+ # documents/iso-10303-41/schemas.yaml.
59
+
60
+ # So the schema.container_path = @config.path is not
61
+ # in fact needed, as the files are already absolute. This notion of
62
+ # using @path to create relative paths was misconceived
63
+ [
64
+ schema.id,
65
+ {
66
+ "path" => path_absolute_to_relative(
67
+ schema.path,
68
+ model.output_path || Dir.pwd,
69
+ ),
70
+ },
71
+ ]
72
+ end
73
+ end
74
+
75
+ def path_relative_to_absolute(relative_path)
76
+ return relative_path if relative_path.nil? || relative_path.empty?
77
+
78
+ eval_path = Pathname.new(relative_path)
79
+ return relative_path if eval_path.absolute?
80
+
81
+ # Or based on current working directory?
82
+ return relative_path unless @path
83
+
84
+ # ... but if this calculates path, we end up expanding it anyway
85
+
86
+ Pathname.new(File.dirname(@path)).join(eval_path).expand_path.to_s
87
+ end
88
+
89
+ def path_absolute_to_relative(absolute_path, container_path)
90
+ return absolute_path if absolute_path.nil? || absolute_path.empty?
91
+
92
+ container_path ||= @path
93
+ return absolute_path unless container_path
94
+ return absolute_path if container_path.empty?
95
+
96
+ p = Pathname.new(container_path)
97
+ container = p.directory? ? p.to_s : p.dirname
98
+
99
+ # Check if absolute_path is actually absolute
100
+ abs_pathname = Pathname.new(absolute_path)
101
+ return absolute_path unless abs_pathname.absolute?
102
+
103
+ abs_pathname.relative_path_from(container).to_s
104
+ end
105
+
106
+ def update_path(new_path)
107
+ if @path.nil?
108
+ @path = new_path
109
+ return @path
110
+ end
111
+
112
+ old_base_path = File.dirname(@path)
113
+ new_base_path = File.dirname(new_path)
114
+ update_schema_path(old_base_path, new_base_path)
115
+
116
+ @path = new_path
117
+ end
118
+
119
+ def concat(another_config)
120
+ unless another_config.is_a?(self.class)
121
+ raise StandardError,
122
+ "Can only concat a SchemaManifest object."
123
+ end
124
+
125
+ # We need to update the relative paths when paths exist
126
+ if path && another_config.path && path != another_config.path
127
+ new_config = another_config.dup
128
+ new_config.update_path(path)
129
+ end
130
+
131
+ schemas.concat(another_config.schemas)
132
+ end
133
+
134
+ def save_to_path(filename)
135
+ new_config = dup.tap do |c|
136
+ c.path = filename
137
+ c.update_path(File.dirname(filename))
138
+ c.output_path = filename
139
+ end
140
+
141
+ File.open(filename, "w") do |f|
142
+ puts "Writing #{filename}..."
143
+ f.write(new_config.to_yaml)
144
+ puts "Done."
145
+ end
146
+ end
147
+
148
+ def update_schema_path(old_base_path, new_base_path)
149
+ schemas.each do |schema|
150
+ schema_path = Pathname.new(schema.path)
151
+ next if schema_path.absolute?
152
+
153
+ schema_path = (Pathname.new(old_base_path) + schema_path).cleanpath
154
+ # This is the new relative schema_path
155
+ schema.path = schema_path.relative_path_from(new_base_path)
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ class SchemaManifestEntry < Lutaml::Model::Serializable
5
+ attribute :id, :string
6
+ attribute :path, :string
7
+ # attribute :schemas_only, :boolean
8
+
9
+ # container_path is a copy of Expressir::SchemaManifest.path,
10
+ # used to resolve the path of each schema within
11
+ # Expressir::SchemaManifest.schemas,
12
+ # when Expressir::SchemaManifest.schemas is recursively flattened
13
+ attr_accessor :container_path
14
+ end
15
+ end
@@ -1,3 +1,8 @@
1
1
  module Expressir
2
- VERSION = "1.2.10".freeze
2
+ # Gem version. Wrapped in a Version module so that lib/expressir.rb can
3
+ # autoload it (Ruby autoload only works for module/class constants, not
4
+ # for string constants like `Expressir::VERSION`).
5
+ module Version
6
+ VERSION = "2.4.29".freeze
7
+ end
3
8
  end