expressir 2.4.29-arm-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 (426) hide show
  1. checksums.yaml +7 -0
  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 +19 -0
  9. data/.github/workflows/release.yml +37 -0
  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 +55 -0
  15. data/.hound.yml +3 -0
  16. data/.rspec +2 -0
  17. data/.rubocop.yml +18 -0
  18. data/.rubocop_todo.yml +297 -0
  19. data/CHANGELOG.md +159 -0
  20. data/Gemfile +18 -0
  21. data/README.adoc +2783 -0
  22. data/Rakefile +41 -0
  23. data/TODO.bugs/01-stale-transformer-autoload.md +39 -0
  24. data/TODO.bugs/02-parser-class-instance-vars.md +36 -0
  25. data/TODO.bugs/03-builder-mutable-state.md +43 -0
  26. data/TODO.bugs/04-formatter-public-send-dispatch.md +53 -0
  27. data/TODO.bugs/05-anonymous-formatter-subclass.md +45 -0
  28. data/TODO.bugs/06-collection-registry-single-source.md +53 -0
  29. data/TODO.bugs/07-require-relative-cleanup.md +42 -0
  30. data/TODO.bugs/08-require-expressir-in-commands.md +34 -0
  31. data/TODO.bugs/09-parser-split.md +53 -0
  32. data/TODO.bugs/10-to-s-override.md +42 -0
  33. data/TODO.bugs/11-parser-class-variables.md +39 -0
  34. data/TODO.bugs/12-marker-modules-vs-registry.md +64 -0
  35. data/TODO.bugs/13-string-literal-scanner-limitation.md +52 -0
  36. data/TODO.bugs/14-model-formatting-leak.md +30 -0
  37. data/TODO.bugs/15-expression-children-macro.md +27 -0
  38. data/TODO.bugs/16-pretty-formatter-duplication.md +28 -0
  39. data/TODO.bugs/17-snake-case-cache-mutable-constant.md +28 -0
  40. data/TODO.bugs/18-const-get-private-constants.md +30 -0
  41. data/TODO.bugs/19-format-methods-public.md +22 -0
  42. data/TODO.bugs/20-coverage-nested-entities-dedup.md +20 -0
  43. data/TODO.bugs/21-operator-tokens-secondary-dispatch.md +21 -0
  44. data/TODO.bugs/22-builder-fast-path-wrappers.md +32 -0
  45. data/TODO.bugs/23-coverage-inverse-maps.md +21 -0
  46. data/TODO.bugs/24-streaming-builder-complexity.md +19 -0
  47. data/TODO.bugs/25-debug-puts-in-production.md +21 -0
  48. data/TODO.bugs/26-generic-entity-children-misplaced.md +21 -0
  49. data/TODO.bugs/27-package-build-god-method.md +19 -0
  50. data/TODO.bugs/28-package-god-class.md +30 -0
  51. data/TODO.bugs/29-validate-ascii-god-class.md +24 -0
  52. data/TODO.bugs/30-unicode-map-extraction.md +19 -0
  53. data/TODO.bugs/README.md +43 -0
  54. data/TODO.max-perf/01-restore-ci-green.md +36 -0
  55. data/TODO.max-perf/02-streaming-parse-path.md +31 -0
  56. data/TODO.max-perf/03-cli-parallel-opt-in.md +27 -0
  57. data/TODO.max-perf/04-benchmark-harness.md +28 -0
  58. data/TODO.max-perf/05-parallel-fidelity-specs.md +22 -0
  59. data/TODO.max-perf/06-builder-cpu-audit.md +41 -0
  60. data/TODO.max-perf/07-upstream-parsanol-roadmap.md +27 -0
  61. data/TODO.max-perf/08-builder-build-perf.md +45 -0
  62. data/TODO.max-perf/09-grammar-cold-start.md +25 -0
  63. data/TODO.max-perf/10-parser-facade-hygiene.md +23 -0
  64. data/TODO.max-perf/11-ci-green-closeout.md +25 -0
  65. data/TODO.max-perf/12-require-boot-profile.md +25 -0
  66. data/TODO.max-perf/13-key-conversion-specs.md +26 -0
  67. data/TODO.max-perf/14-builder-call-handler-audit.md +28 -0
  68. data/TODO.parity-ee/00-overview.md +76 -0
  69. data/TODO.parity-ee/01-annex-g-rule-extraction.md +41 -0
  70. data/TODO.parity-ee/02-eeng-algorithm-inventory.md +8 -0
  71. data/TODO.parity-ee/03-eeng-oracle-harness.md +33 -0
  72. data/TODO.parity-ee/04-shtolo-concatenate.md +44 -0
  73. data/TODO.parity-ee/05-shtolo-longform-flatten.md +53 -0
  74. data/TODO.parity-ee/06-interface-scheduling-parity.md +47 -0
  75. data/TODO.parity-ee/07-semantic-checks-port.md +35 -0
  76. data/TODO.parity-ee/08-pretty-roundtrip-gate.md +27 -0
  77. data/TODO.parity-ee/09-smrl-index-and-listing.md +22 -0
  78. data/TODO.parity-ee/10-interface-dot-graph.md +21 -0
  79. data/TODO.parity-ee/11-import-eeng-tests.md +79 -0
  80. data/TODO.parity-ee/12-full-check-catalog.md +67 -0
  81. data/TODO.parity-ee/13-population-p21.md +54 -0
  82. data/TODO.parity-ee/14-shtolo-completion.md +44 -0
  83. data/TODO.parity-ee/15-part28-xml.md +51 -0
  84. data/TODO.parity-ee/16-compare-patch.md +48 -0
  85. data/TODO.parity-ee/17-official-tests.md +42 -0
  86. data/TODO.parity-ee/18-mim-mapping.md +47 -0
  87. data/TODO.parity-ee/19-architecture.md +97 -0
  88. data/TODO.parity-ee/parity-matrix.md +108 -0
  89. data/TODO.refpath-v2/00-overview.md +64 -0
  90. data/TODO.suma-improvements/00-overview.md +23 -0
  91. data/TODO.suma-improvements/01-prebuilt-platform-gems.md +33 -0
  92. data/TODO.suma-improvements/02-suma-e2e.md +39 -0
  93. data/TODO.suma-improvements/03-item-graph.md +22 -0
  94. data/TODO.suma-improvements/04-compiled-set-default.md +16 -0
  95. data/TODO.suma-improvements/05-validation-in-docs.md +17 -0
  96. data/TODO.suma-improvements/06-memory-remeasure.md +36 -0
  97. data/TODO.suma-improvements/07-part28-xml.md +15 -0
  98. data/TODO.suma-improvements/08-windows-gnu-toolchain.md +15 -0
  99. data/TODO.suma-improvements/09-checker-tranche3.md +13 -0
  100. data/TODO.suma-improvements/10-expressdoc.md +8 -0
  101. data/benchmark/srl_benchmark.rb +458 -0
  102. data/benchmark/srl_native_benchmark.rb +146 -0
  103. data/benchmark/srl_ruby_benchmark.rb +132 -0
  104. data/bin/console +11 -0
  105. data/bin/rspec +30 -0
  106. data/bin/setup +8 -0
  107. data/docs/Gemfile +12 -0
  108. data/docs/_config.yml +141 -0
  109. data/docs/_guides/changes/changes-format.adoc +778 -0
  110. data/docs/_guides/changes/importing-eengine.adoc +898 -0
  111. data/docs/_guides/changes/index.adoc +396 -0
  112. data/docs/_guides/changes/programmatic-usage.adoc +1038 -0
  113. data/docs/_guides/changes/validating-changes.adoc +681 -0
  114. data/docs/_guides/cli/benchmark-performance.adoc +834 -0
  115. data/docs/_guides/cli/coverage-analysis.adoc +921 -0
  116. data/docs/_guides/cli/format-schemas.adoc +547 -0
  117. data/docs/_guides/cli/index.adoc +8 -0
  118. data/docs/_guides/cli/managing-changes.adoc +927 -0
  119. data/docs/_guides/cli/validate-ascii.adoc +645 -0
  120. data/docs/_guides/cli/validate-schemas.adoc +534 -0
  121. data/docs/_guides/formatter/formatter-architecture.adoc +401 -0
  122. data/docs/_guides/index.adoc +165 -0
  123. data/docs/_guides/ler/creating-packages.adoc +664 -0
  124. data/docs/_guides/ler/index.adoc +305 -0
  125. data/docs/_guides/ler/loading-packages.adoc +707 -0
  126. data/docs/_guides/ler/package-formats.adoc +748 -0
  127. data/docs/_guides/ler/querying-packages.adoc +826 -0
  128. data/docs/_guides/ler/step-packages.adoc +385 -0
  129. data/docs/_guides/ler/validating-packages.adoc +750 -0
  130. data/docs/_guides/liquid/basic-templates.adoc +813 -0
  131. data/docs/_guides/liquid/documentation-generation.adoc +1042 -0
  132. data/docs/_guides/liquid/drops-reference.adoc +829 -0
  133. data/docs/_guides/liquid/filters-and-tags.adoc +912 -0
  134. data/docs/_guides/liquid/index.adoc +468 -0
  135. data/docs/_guides/manifests/creating-manifests.adoc +483 -0
  136. data/docs/_guides/manifests/index.adoc +307 -0
  137. data/docs/_guides/manifests/resolving-manifests.adoc +557 -0
  138. data/docs/_guides/manifests/validating-manifests.adoc +713 -0
  139. data/docs/_guides/ruby-api/formatting-schemas.adoc +605 -0
  140. data/docs/_guides/ruby-api/index.adoc +257 -0
  141. data/docs/_guides/ruby-api/parsing-files.adoc +421 -0
  142. data/docs/_guides/ruby-api/search-engine.adoc +609 -0
  143. data/docs/_guides/ruby-api/working-with-repository.adoc +577 -0
  144. data/docs/_pages/data-model.adoc +665 -0
  145. data/docs/_pages/express-language.adoc +506 -0
  146. data/docs/_pages/getting-started.adoc +414 -0
  147. data/docs/_pages/index.adoc +116 -0
  148. data/docs/_pages/introduction.adoc +256 -0
  149. data/docs/_pages/ler-packages.adoc +837 -0
  150. data/docs/_pages/parsers.adoc +709 -0
  151. data/docs/_pages/schema-manifests.adoc +431 -0
  152. data/docs/_references/index.adoc +228 -0
  153. data/docs/_tutorials/creating-ler-package.adoc +735 -0
  154. data/docs/_tutorials/documentation-coverage.adoc +795 -0
  155. data/docs/_tutorials/formatting-schemas.adoc +89 -0
  156. data/docs/_tutorials/index.adoc +231 -0
  157. data/docs/_tutorials/liquid-templates.adoc +806 -0
  158. data/docs/_tutorials/parsing-your-first-schema.adoc +522 -0
  159. data/docs/_tutorials/querying-schemas.adoc +751 -0
  160. data/docs/_tutorials/working-with-multiple-schemas.adoc +676 -0
  161. data/docs/index.adoc +242 -0
  162. data/docs/lychee.toml +90 -0
  163. data/examples/demo_ler_usage.sh +86 -0
  164. data/examples/ler/README.md +111 -0
  165. data/examples/ler/simple_example.ler +0 -0
  166. data/examples/ler/simple_schema.exp +33 -0
  167. data/examples/ler_build.rb +75 -0
  168. data/examples/ler_cli.rb +79 -0
  169. data/examples/ler_demo_complete.rb +276 -0
  170. data/examples/ler_query.rb +91 -0
  171. data/examples/ler_query_examples.rb +305 -0
  172. data/examples/ler_stats.rb +81 -0
  173. data/examples/phase3_demo.rb +159 -0
  174. data/examples/query_demo_simple.rb +131 -0
  175. data/exe/expressir +11 -0
  176. data/exe/expressir-format +14 -0
  177. data/exe/expressir-format-test +82 -0
  178. data/expressir.gemspec +61 -0
  179. data/lib/expressir/3.2/expressir_core.so +0 -0
  180. data/lib/expressir/3.3/expressir_core.so +0 -0
  181. data/lib/expressir/3.4/expressir_core.so +0 -0
  182. data/lib/expressir/4.0/expressir_core.so +0 -0
  183. data/lib/expressir/benchmark.rb +310 -0
  184. data/lib/expressir/changes/item_change.rb +20 -0
  185. data/lib/expressir/changes/mapping_change.rb +16 -0
  186. data/lib/expressir/changes/schema_change.rb +85 -0
  187. data/lib/expressir/changes/version_change.rb +26 -0
  188. data/lib/expressir/changes.rb +9 -0
  189. data/lib/expressir/cli.rb +148 -0
  190. data/lib/expressir/commands/base.rb +25 -0
  191. data/lib/expressir/commands/benchmark.rb +59 -0
  192. data/lib/expressir/commands/benchmark_cache.rb +80 -0
  193. data/lib/expressir/commands/changes.rb +34 -0
  194. data/lib/expressir/commands/changes_import_eengine.rb +146 -0
  195. data/lib/expressir/commands/changes_validate.rb +63 -0
  196. data/lib/expressir/commands/check.rb +56 -0
  197. data/lib/expressir/commands/clean.rb +20 -0
  198. data/lib/expressir/commands/coverage.rb +458 -0
  199. data/lib/expressir/commands/expand.rb +26 -0
  200. data/lib/expressir/commands/file_violations.rb +70 -0
  201. data/lib/expressir/commands/fix.rb +33 -0
  202. data/lib/expressir/commands/flatten.rb +29 -0
  203. data/lib/expressir/commands/format.rb +43 -0
  204. data/lib/expressir/commands/manifest.rb +420 -0
  205. data/lib/expressir/commands/mapping_validate.rb +68 -0
  206. data/lib/expressir/commands/non_ascii_character.rb +49 -0
  207. data/lib/expressir/commands/non_ascii_violation_collection.rb +301 -0
  208. data/lib/expressir/commands/package.rb +1222 -0
  209. data/lib/expressir/commands/parity_inputs.rb +160 -0
  210. data/lib/expressir/commands/validate.rb +106 -0
  211. data/lib/expressir/commands/validate_ascii.rb +94 -0
  212. data/lib/expressir/commands/validate_load.rb +91 -0
  213. data/lib/expressir/commands/version.rb +9 -0
  214. data/lib/expressir/commands/xsd.rb +23 -0
  215. data/lib/expressir/commands.rb +30 -0
  216. data/lib/expressir/config.rb +60 -0
  217. data/lib/expressir/coverage.rb +510 -0
  218. data/lib/expressir/eengine/arm_compare_report.rb +23 -0
  219. data/lib/expressir/eengine/changes_section.rb +16 -0
  220. data/lib/expressir/eengine/compare_report.rb +69 -0
  221. data/lib/expressir/eengine/mim_compare_report.rb +23 -0
  222. data/lib/expressir/eengine/modified_object.rb +21 -0
  223. data/lib/expressir/eengine.rb +9 -0
  224. data/lib/expressir/errors.rb +113 -0
  225. data/lib/expressir/express/adoc_hyperlink_formatter.rb +30 -0
  226. data/lib/expressir/express/adoc_source_formatter.rb +12 -0
  227. data/lib/expressir/express/ast_key_converter.rb +114 -0
  228. data/lib/expressir/express/builder.rb +277 -0
  229. data/lib/expressir/express/builder_context.rb +22 -0
  230. data/lib/expressir/express/builder_registry.rb +397 -0
  231. data/lib/expressir/express/builders/attribute_decl_builder.rb +32 -0
  232. data/lib/expressir/express/builders/built_in_builder.rb +75 -0
  233. data/lib/expressir/express/builders/constant_builder.rb +108 -0
  234. data/lib/expressir/express/builders/declaration_builder.rb +20 -0
  235. data/lib/expressir/express/builders/derive_clause_builder.rb +14 -0
  236. data/lib/expressir/express/builders/derived_attr_builder.rb +28 -0
  237. data/lib/expressir/express/builders/domain_rule_builder.rb +21 -0
  238. data/lib/expressir/express/builders/entity_decl_builder.rb +116 -0
  239. data/lib/expressir/express/builders/explicit_attr_builder.rb +49 -0
  240. data/lib/expressir/express/builders/expression_builder.rb +416 -0
  241. data/lib/expressir/express/builders/function_decl_builder.rb +86 -0
  242. data/lib/expressir/express/builders/helpers.rb +148 -0
  243. data/lib/expressir/express/builders/interface_builder.rb +151 -0
  244. data/lib/expressir/express/builders/inverse_attr_builder.rb +43 -0
  245. data/lib/expressir/express/builders/inverse_attr_type_builder.rb +30 -0
  246. data/lib/expressir/express/builders/inverse_clause_builder.rb +14 -0
  247. data/lib/expressir/express/builders/literal_builder.rb +93 -0
  248. data/lib/expressir/express/builders/procedure_decl_builder.rb +82 -0
  249. data/lib/expressir/express/builders/qualifier_builder.rb +102 -0
  250. data/lib/expressir/express/builders/reference_builder.rb +18 -0
  251. data/lib/expressir/express/builders/rule_decl_builder.rb +97 -0
  252. data/lib/expressir/express/builders/schema_body_decl_builder.rb +18 -0
  253. data/lib/expressir/express/builders/schema_decl_builder.rb +56 -0
  254. data/lib/expressir/express/builders/schema_version_builder.rb +34 -0
  255. data/lib/expressir/express/builders/simple_id_builder.rb +17 -0
  256. data/lib/expressir/express/builders/statement_builder.rb +243 -0
  257. data/lib/expressir/express/builders/subtype_constraint_builder.rb +166 -0
  258. data/lib/expressir/express/builders/syntax_builder.rb +30 -0
  259. data/lib/expressir/express/builders/type_builder.rb +238 -0
  260. data/lib/expressir/express/builders/type_decl_builder.rb +26 -0
  261. data/lib/expressir/express/builders/unique_clause_builder.rb +20 -0
  262. data/lib/expressir/express/builders/unique_rule_builder.rb +41 -0
  263. data/lib/expressir/express/builders/where_clause_builder.rb +20 -0
  264. data/lib/expressir/express/builders.rb +55 -0
  265. data/lib/expressir/express/cache.rb +76 -0
  266. data/lib/expressir/express/checker.rb +812 -0
  267. data/lib/expressir/express/concatenator.rb +79 -0
  268. data/lib/expressir/express/core.rb +95 -0
  269. data/lib/expressir/express/error.rb +124 -0
  270. data/lib/expressir/express/formatter.rb +149 -0
  271. data/lib/expressir/express/formatters/data_types_formatter.rb +362 -0
  272. data/lib/expressir/express/formatters/declarations_formatter.rb +753 -0
  273. data/lib/expressir/express/formatters/expressions_formatter.rb +180 -0
  274. data/lib/expressir/express/formatters/literals_formatter.rb +55 -0
  275. data/lib/expressir/express/formatters/references_formatter.rb +53 -0
  276. data/lib/expressir/express/formatters/remark_formatter.rb +270 -0
  277. data/lib/expressir/express/formatters/remark_item_formatter.rb +28 -0
  278. data/lib/expressir/express/formatters/statements_formatter.rb +272 -0
  279. data/lib/expressir/express/formatters/supertype_expressions_formatter.rb +54 -0
  280. data/lib/expressir/express/formatters.rb +22 -0
  281. data/lib/expressir/express/grammar/parser.rb +712 -0
  282. data/lib/expressir/express/grammar.rb +11 -0
  283. data/lib/expressir/express/hyperlink_formatter.rb +35 -0
  284. data/lib/expressir/express/interface_dot.rb +105 -0
  285. data/lib/expressir/express/lazy_repository.rb +211 -0
  286. data/lib/expressir/express/line_map.rb +48 -0
  287. data/lib/expressir/express/listing.rb +174 -0
  288. data/lib/expressir/express/model_traversal.rb +42 -0
  289. data/lib/expressir/express/model_visitor.rb +25 -0
  290. data/lib/expressir/express/node_position_index.rb +342 -0
  291. data/lib/expressir/express/parallel_files.rb +229 -0
  292. data/lib/expressir/express/parser.rb +523 -0
  293. data/lib/expressir/express/pretty_formatter.rb +586 -0
  294. data/lib/expressir/express/pretty_gate.rb +61 -0
  295. data/lib/expressir/express/refs_overlay.rb +47 -0
  296. data/lib/expressir/express/remark_attacher.rb +1098 -0
  297. data/lib/expressir/express/remark_overlay.rb +86 -0
  298. data/lib/expressir/express/remark_scanner.rb +245 -0
  299. data/lib/expressir/express/resolve_references_model_visitor.rb +29 -0
  300. data/lib/expressir/express/schema_block_scanner.rb +137 -0
  301. data/lib/expressir/express/schema_head_formatter.rb +22 -0
  302. data/lib/expressir/express/schema_plain_source_formatter.rb +11 -0
  303. data/lib/expressir/express/schema_source_formatter.rb +15 -0
  304. data/lib/expressir/express/scope_resolver.rb +223 -0
  305. data/lib/expressir/express/self_schema_reference.rb +126 -0
  306. data/lib/expressir/express/shtolo.rb +679 -0
  307. data/lib/expressir/express/smrl_xml.rb +125 -0
  308. data/lib/expressir/express/source_formatter.rb +15 -0
  309. data/lib/expressir/express/streaming_builder.rb +435 -0
  310. data/lib/expressir/express/xsd.rb +259 -0
  311. data/lib/expressir/express.rb +53 -0
  312. data/lib/expressir/liquid.rb +1 -0
  313. data/lib/expressir/manifest/resolver.rb +210 -0
  314. data/lib/expressir/manifest/validator.rb +192 -0
  315. data/lib/expressir/manifest.rb +6 -0
  316. data/lib/expressir/mapping/refpath.rb +857 -0
  317. data/lib/expressir/mapping.rb +253 -0
  318. data/lib/expressir/model/cache.rb +18 -0
  319. data/lib/expressir/model/concerns.rb +42 -0
  320. data/lib/expressir/model/data_types/aggregate.rb +26 -0
  321. data/lib/expressir/model/data_types/array.rb +25 -0
  322. data/lib/expressir/model/data_types/bag.rb +21 -0
  323. data/lib/expressir/model/data_types/binary.rb +19 -0
  324. data/lib/expressir/model/data_types/boolean.rb +15 -0
  325. data/lib/expressir/model/data_types/enumeration.rb +21 -0
  326. data/lib/expressir/model/data_types/enumeration_item.rb +24 -0
  327. data/lib/expressir/model/data_types/generic.rb +24 -0
  328. data/lib/expressir/model/data_types/generic_entity.rb +24 -0
  329. data/lib/expressir/model/data_types/integer.rb +15 -0
  330. data/lib/expressir/model/data_types/list.rb +23 -0
  331. data/lib/expressir/model/data_types/logical.rb +15 -0
  332. data/lib/expressir/model/data_types/number.rb +15 -0
  333. data/lib/expressir/model/data_types/real.rb +17 -0
  334. data/lib/expressir/model/data_types/select.rb +23 -0
  335. data/lib/expressir/model/data_types/set.rb +21 -0
  336. data/lib/expressir/model/data_types/string.rb +19 -0
  337. data/lib/expressir/model/data_types.rb +25 -0
  338. data/lib/expressir/model/declarations/attribute.rb +38 -0
  339. data/lib/expressir/model/declarations/constant.rb +28 -0
  340. data/lib/expressir/model/declarations/derived_attribute.rb +25 -0
  341. data/lib/expressir/model/declarations/entity.rb +62 -0
  342. data/lib/expressir/model/declarations/function.rb +59 -0
  343. data/lib/expressir/model/declarations/informal_proposition_rule.rb +25 -0
  344. data/lib/expressir/model/declarations/interface.rb +37 -0
  345. data/lib/expressir/model/declarations/interface_item.rb +21 -0
  346. data/lib/expressir/model/declarations/interfaced_item.rb +33 -0
  347. data/lib/expressir/model/declarations/inverse_attribute.rb +25 -0
  348. data/lib/expressir/model/declarations/parameter.rb +28 -0
  349. data/lib/expressir/model/declarations/procedure.rb +57 -0
  350. data/lib/expressir/model/declarations/remark_item.rb +21 -0
  351. data/lib/expressir/model/declarations/rule.rb +66 -0
  352. data/lib/expressir/model/declarations/schema.rb +215 -0
  353. data/lib/expressir/model/declarations/schema_version.rb +19 -0
  354. data/lib/expressir/model/declarations/schema_version_item.rb +19 -0
  355. data/lib/expressir/model/declarations/subtype_constraint.rb +32 -0
  356. data/lib/expressir/model/declarations/type.rb +45 -0
  357. data/lib/expressir/model/declarations/unique_rule.rb +26 -0
  358. data/lib/expressir/model/declarations/variable.rb +28 -0
  359. data/lib/expressir/model/declarations/where_rule.rb +26 -0
  360. data/lib/expressir/model/declarations.rb +31 -0
  361. data/lib/expressir/model/dependency_resolver.rb +268 -0
  362. data/lib/expressir/model/exp_file.rb +42 -0
  363. data/lib/expressir/model/expressions/aggregate_initializer.rb +18 -0
  364. data/lib/expressir/model/expressions/aggregate_initializer_item.rb +20 -0
  365. data/lib/expressir/model/expressions/binary_expression.rb +59 -0
  366. data/lib/expressir/model/expressions/entity_constructor.rb +20 -0
  367. data/lib/expressir/model/expressions/function_call.rb +20 -0
  368. data/lib/expressir/model/expressions/interval.rb +29 -0
  369. data/lib/expressir/model/expressions/query_expression.rb +31 -0
  370. data/lib/expressir/model/expressions/unary_expression.rb +25 -0
  371. data/lib/expressir/model/expressions.rb +18 -0
  372. data/lib/expressir/model/identifier.rb +26 -0
  373. data/lib/expressir/model/indexes/entity_index.rb +103 -0
  374. data/lib/expressir/model/indexes/item_graph.rb +185 -0
  375. data/lib/expressir/model/indexes/reference_index.rb +148 -0
  376. data/lib/expressir/model/indexes/type_index.rb +149 -0
  377. data/lib/expressir/model/indexes.rb +12 -0
  378. data/lib/expressir/model/interface_validator.rb +384 -0
  379. data/lib/expressir/model/literals/binary.rb +17 -0
  380. data/lib/expressir/model/literals/integer.rb +17 -0
  381. data/lib/expressir/model/literals/logical.rb +21 -0
  382. data/lib/expressir/model/literals/real.rb +17 -0
  383. data/lib/expressir/model/literals/string.rb +20 -0
  384. data/lib/expressir/model/literals.rb +13 -0
  385. data/lib/expressir/model/model_element.rb +377 -0
  386. data/lib/expressir/model/references/attribute_reference.rb +19 -0
  387. data/lib/expressir/model/references/group_reference.rb +19 -0
  388. data/lib/expressir/model/references/index_reference.rb +23 -0
  389. data/lib/expressir/model/references/simple_reference.rb +21 -0
  390. data/lib/expressir/model/references.rb +12 -0
  391. data/lib/expressir/model/remark_format.rb +17 -0
  392. data/lib/expressir/model/remark_info.rb +92 -0
  393. data/lib/expressir/model/remark_placement.rb +42 -0
  394. data/lib/expressir/model/repository.rb +483 -0
  395. data/lib/expressir/model/repository_validator.rb +293 -0
  396. data/lib/expressir/model/search_engine.rb +551 -0
  397. data/lib/expressir/model/statements/alias.rb +31 -0
  398. data/lib/expressir/model/statements/assignment.rb +23 -0
  399. data/lib/expressir/model/statements/case.rb +42 -0
  400. data/lib/expressir/model/statements/case_action.rb +20 -0
  401. data/lib/expressir/model/statements/compound.rb +21 -0
  402. data/lib/expressir/model/statements/escape.rb +18 -0
  403. data/lib/expressir/model/statements/if.rb +26 -0
  404. data/lib/expressir/model/statements/null.rb +18 -0
  405. data/lib/expressir/model/statements/procedure_call.rb +22 -0
  406. data/lib/expressir/model/statements/repeat.rb +40 -0
  407. data/lib/expressir/model/statements/return.rb +20 -0
  408. data/lib/expressir/model/statements/skip.rb +18 -0
  409. data/lib/expressir/model/statements.rb +20 -0
  410. data/lib/expressir/model/supertype_expressions/binary_supertype_expression.rb +25 -0
  411. data/lib/expressir/model/supertype_expressions/oneof_supertype_expression.rb +17 -0
  412. data/lib/expressir/model/supertype_expressions.rb +12 -0
  413. data/lib/expressir/model.rb +39 -0
  414. data/lib/expressir/package/builder.rb +231 -0
  415. data/lib/expressir/package/metadata.rb +79 -0
  416. data/lib/expressir/package/reader.rb +149 -0
  417. data/lib/expressir/package.rb +8 -0
  418. data/lib/expressir/schema_manifest.rb +159 -0
  419. data/lib/expressir/schema_manifest_entry.rb +15 -0
  420. data/lib/expressir/version.rb +8 -0
  421. data/lib/expressir.rb +94 -0
  422. data/lib/tasks/verify_remarks.rake +16 -0
  423. data/rakelib/native.rake +24 -0
  424. data/rakelib/oracle.rake +52 -0
  425. data/rakelib/verify_remarks.rake +16 -0
  426. metadata +692 -0
@@ -0,0 +1,148 @@
1
+ require "thor"
2
+ require "yaml"
3
+
4
+ module Expressir
5
+ class Cli < Thor
6
+ # Exit with error code on command failures
7
+ def self.exit_on_failure?
8
+ true
9
+ end
10
+
11
+ desc "format PATH", "pretty print EXPRESS schema located at PATH"
12
+ method_option :profile, type: :string,
13
+ desc: "Formatting profile: 'iso' (ISO/TC 184/SC 4) or 'elf' (ELF Pretty Print)",
14
+ default: "iso"
15
+ method_option :indent, type: :numeric,
16
+ desc: "Indentation width (ELF profile only)",
17
+ default: 4
18
+ method_option :provenance, type: :boolean,
19
+ desc: "Include provenance information (ELF profile only)",
20
+ default: true
21
+ def format(path, _thor_options = nil)
22
+ Expressir::Commands::Format.new(options).run(path)
23
+ end
24
+
25
+ desc "clean PATH", "Strip remarks and prettify EXPRESS schema at PATH"
26
+ method_option :output, type: :string,
27
+ desc: "Output file path (defaults to stdout)"
28
+ def clean(path, _thor_options = nil)
29
+ Expressir::Commands::Clean.new(options).run(path)
30
+ end
31
+
32
+ desc "fix PATH",
33
+ "Rewrite self-schema-qualified references (#125) in the EXPRESS schema at PATH"
34
+ method_option :output, type: :string,
35
+ aliases: "-o",
36
+ desc: "Output file path (defaults to stdout)"
37
+ def fix(path, _thor_options = nil)
38
+ Expressir::Commands::Fix.new(options).run(path)
39
+ end
40
+
41
+ desc "expand PATH",
42
+ "Concatenate the interface closure of PATH into one .exp artifact"
43
+ method_option :output, type: :string,
44
+ aliases: "-o",
45
+ desc: "Output file path (defaults to stdout)"
46
+ method_option :manifest, type: :string,
47
+ desc: "ELF schema manifest YAML defining where schemas live " \
48
+ "(primary resolution mode)"
49
+ method_option :stepmod, type: :string,
50
+ desc: "STEPmod checkout root — explicit opt-in to directory-" \
51
+ "convention resolution as the fallback"
52
+ def expand(path, _thor_options = nil)
53
+ Expressir::Commands::Expand.new(options).run(path)
54
+ end
55
+
56
+ desc "flatten PATH",
57
+ "Flatten the interface closure of PATH into an ISO 10303-11:1994 longform schema"
58
+ method_option :output, type: :string,
59
+ aliases: "-o",
60
+ desc: "Output file path (defaults to stdout)"
61
+ method_option :longform_name, type: :string,
62
+ desc: "Longform SCHEMA id (default: <root>_lf)"
63
+ method_option :extenders, type: :string,
64
+ desc: "Extensible type handling: 'all' (default, fold every " \
65
+ "extender in the closure per Annex G.2.3/G.2.4) or " \
66
+ "'none' (leave extensible types as declared)"
67
+ method_option :manifest, type: :string,
68
+ desc: "ELF schema manifest YAML defining where schemas live " \
69
+ "(primary resolution mode)"
70
+ method_option :stepmod, type: :string,
71
+ desc: "STEPmod checkout root — explicit opt-in to directory-" \
72
+ "convention resolution as the fallback"
73
+ def flatten(path, _thor_options = nil)
74
+ Expressir::Commands::Flatten.new(options).run(path)
75
+ end
76
+
77
+ desc "benchmark FILE_OR_YAML",
78
+ "Benchmark schema loading performance for a file or list of files from YAML"
79
+ method_option :ips, type: :boolean,
80
+ desc: "Use benchmark-ips for detailed statistics"
81
+ method_option :verbose, type: :boolean, desc: "Show verbose output"
82
+ method_option :save, type: :boolean, desc: "Save benchmark results to file"
83
+ method_option :format, type: :string,
84
+ desc: "Output format (json, csv, default)"
85
+ def benchmark(path, _thor_options = nil)
86
+ Expressir::Commands::Benchmark.new(options).run(path)
87
+ end
88
+
89
+ desc "benchmark-cache FILE_OR_YAML", "Benchmark schema loading with caching"
90
+ method_option :ips, type: :boolean,
91
+ desc: "Use benchmark-ips for detailed statistics"
92
+ method_option :verbose, type: :boolean, desc: "Show verbose output"
93
+ method_option :save, type: :boolean, desc: "Save benchmark results to file"
94
+ method_option :format, type: :string,
95
+ desc: "Output format (json, csv, default)"
96
+ method_option :cache_path, type: :string,
97
+ desc: "Path to store the cache file"
98
+ def benchmark_cache(path, _thor_options = nil)
99
+ Expressir::Commands::BenchmarkCache.new(options).run(path)
100
+ end
101
+
102
+ desc "mapping_validate PATH", "Validate <<express:...>> links in a module mapping.yaml against its ARM/MIM closure"
103
+ def mapping_validate(path)
104
+ Expressir::Commands::MappingValidate.new(options).run(path)
105
+ end
106
+
107
+ desc "xsd PATH", "Write an XML Schema rendering of the EXPRESS schema at PATH"
108
+ method_option :output, type: :string, aliases: "-o",
109
+ desc: "Output file path (defaults to stdout)"
110
+ def xsd(path)
111
+ Expressir::Commands::Xsd.new(options).run(path)
112
+ end
113
+
114
+ desc "validate SUBCOMMAND", "EXPRESS schema validation commands"
115
+ subcommand "validate", Expressir::Commands::Validate
116
+
117
+ desc "coverage *PATH",
118
+ "List EXPRESS entities and check documentation coverage"
119
+ method_option :format, type: :string,
120
+ desc: "Output format (text, json, yaml)", default: "text"
121
+ method_option :exclude, type: :string,
122
+ desc: "Comma-separated list of EXPRESS entity types to skip from coverage (e.g., TYPE,CONSTANT,TYPE:SELECT)"
123
+ method_option :output, type: :string,
124
+ desc: "Output file path for JSON/YAML formats (defaults to coverage_report.json/yaml)"
125
+ method_option :ignore_files, type: :string,
126
+ desc: "Path to YAML file containing array of files to ignore from overall coverage calculation"
127
+ method_option :max_processes, type: :numeric,
128
+ default: Expressir::Express::ParallelFiles::DEFAULT_MAX_PROCESSES,
129
+ desc: "Parallel parse workers (1 = sequential; falls back to sequential where fork is unavailable)"
130
+ def coverage(*paths)
131
+ Expressir::Commands::Coverage.new(options).run(paths)
132
+ end
133
+
134
+ desc "changes SUBCOMMAND", "Commands for EXPRESS Changes files"
135
+ subcommand "changes", Expressir::Commands::Changes
136
+
137
+ desc "manifest SUBCOMMAND", "Schema manifest management commands"
138
+ subcommand "manifest", Expressir::Commands::Manifest
139
+
140
+ desc "package SUBCOMMAND", "LER package management commands"
141
+ subcommand "package", Expressir::Commands::Package
142
+
143
+ desc "version", "Expressir Version"
144
+ def version
145
+ Expressir::Commands::Version.new(options).run
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,25 @@
1
+ module Expressir
2
+ module Commands
3
+ class Base
4
+ attr_reader :options
5
+
6
+ def initialize(options = {})
7
+ @options = options
8
+ end
9
+
10
+ # Common utilities that all commands might need
11
+ def say(message)
12
+ # Use instance variable for testability - if output is set, use it
13
+ if defined?(@output) && @output
14
+ @output.puts(message)
15
+ else
16
+ puts(message)
17
+ end
18
+ end
19
+
20
+ def exit_with_error(message, _exit_code = 1)
21
+ raise Expressir::CommandError.new(message)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,59 @@
1
+ module Expressir
2
+ module Commands
3
+ class Benchmark < Base
4
+ def run(path)
5
+ configure_benchmarking
6
+
7
+ if [".yml", ".yaml"].include?(File.extname(path).downcase)
8
+ benchmark_from_manifest(path)
9
+ else
10
+ benchmark_file(path)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def configure_benchmarking
17
+ Expressir.configuration.benchmark_enabled = true
18
+ Expressir.configuration.benchmark_ips = options[:ips]
19
+ Expressir.configuration.benchmark_verbose = options[:verbose]
20
+ Expressir.configuration.benchmark_save = options[:save]
21
+ Expressir.configuration.benchmark_format = options[:format] if options[:format]
22
+ end
23
+
24
+ def benchmark_file(path)
25
+ say "Express Schema Loading Benchmark"
26
+ say "--------------------------------"
27
+
28
+ repository = Expressir::Benchmark.measure_file(path) do
29
+ Expressir::Express::Parser.from_file(path)
30
+ end
31
+
32
+ if repository
33
+ say "Loaded #{repository.schemas.size} schemas"
34
+ else
35
+ say "Failed to load schema"
36
+ end
37
+ end
38
+
39
+ def benchmark_from_manifest(manifest_path)
40
+ say "Express Schema Loading Benchmark from Manifest"
41
+ say "--------------------------------"
42
+
43
+ # Load schema manifest
44
+ manifest = Expressir::SchemaManifest.from_file(manifest_path)
45
+ schema_files = manifest.schemas.map(&:path)
46
+
47
+ say "Manifest File: #{manifest_path}"
48
+ say "Number of schemas in list: #{schema_files.size}"
49
+ say "--------------------------------"
50
+
51
+ # Load the schemas
52
+ Expressir::Benchmark.measure_collection(schema_files) do |file|
53
+ repository = Expressir::Express::Parser.from_file(file)
54
+ repository.schemas
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,80 @@
1
+ module Expressir
2
+ module Commands
3
+ class BenchmarkCache < Base
4
+ def run(path)
5
+ configure_benchmarking
6
+
7
+ # Run benchmarks with cache
8
+ cache_path = options[:cache_path] || generate_temp_cache_path
9
+
10
+ if [".yml", ".yaml"].include?(File.extname(path).downcase)
11
+ benchmark_cache_from_manifest(path, cache_path)
12
+ else
13
+ benchmark_cache_file(path, cache_path)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def configure_benchmarking
20
+ Expressir.configuration.benchmark_enabled = true
21
+ Expressir.configuration.benchmark_ips = options[:ips]
22
+ Expressir.configuration.benchmark_verbose = options[:verbose]
23
+ Expressir.configuration.benchmark_save = options[:save]
24
+ Expressir.configuration.benchmark_format = options[:format] if options[:format]
25
+ end
26
+
27
+ def benchmark_cache_file(path, cache_path)
28
+ say "Express Schema Loading Benchmark with Caching"
29
+ say "--------------------------------"
30
+ say "Schema: #{path}"
31
+ say "Cache: #{cache_path}"
32
+ say "--------------------------------"
33
+
34
+ # Benchmark with caching
35
+ results = Expressir::Benchmark.measure_with_cache(path,
36
+ cache_path) do |file|
37
+ Expressir::Express::Parser.from_file(file)
38
+ end
39
+
40
+ if results[:repository]
41
+ schema_count = results[:repository].schemas.size
42
+ say "Loaded #{schema_count} schemas"
43
+ else
44
+ say "Failed to load schema"
45
+ end
46
+ end
47
+
48
+ def benchmark_cache_from_manifest(manifest_path, cache_path)
49
+ say "Express Schema Loading Benchmark with Caching from Manifest"
50
+ say "--------------------------------"
51
+
52
+ # Load schema manifest
53
+ manifest = Expressir::SchemaManifest.from_file(manifest_path)
54
+ schema_files = manifest.schemas.map(&:path)
55
+
56
+ say "Manifest File: #{manifest_path}"
57
+ say "Number of schemas in list: #{schema_files.size}"
58
+ say "Cache: #{cache_path}"
59
+ say "--------------------------------"
60
+
61
+ # Process each file with caching
62
+ schema_files.each_with_index do |file, index|
63
+ say "Processing file #{index + 1}/#{schema_files.size}: #{file}"
64
+
65
+ # Benchmark with caching
66
+ Expressir::Benchmark.measure_with_cache(file, cache_path) do |path|
67
+ Expressir::Express::Parser.from_file(path)
68
+ end
69
+
70
+ say "--------------------------------"
71
+ end
72
+ end
73
+
74
+ def generate_temp_cache_path
75
+ require "tempfile"
76
+ Tempfile.new(["expressir_cache", ".bin"]).path
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+
5
+ module Expressir
6
+ module Commands
7
+ # Thor subcommand for EXPRESS Changes file operations
8
+ class Changes < Thor
9
+ desc "validate PATH", "Validate EXPRESS Changes YAML file"
10
+ method_option :normalize, type: :boolean,
11
+ desc: "Normalize file through round-trip serialization"
12
+ method_option :in_place, type: :boolean,
13
+ desc: "Update file in place (requires --normalize)"
14
+ method_option :output, type: :string,
15
+ desc: "Output file path (for normalized output)"
16
+ method_option :verbose, type: :boolean,
17
+ desc: "Show verbose output"
18
+ def validate(path)
19
+ ChangesValidate.new(options).run(path)
20
+ end
21
+
22
+ desc "import-eengine INPUT_XML SCHEMA_NAME VERSION",
23
+ "Import eengine comparison XML to EXPRESS Changes YAML"
24
+ method_option :output, type: :string, aliases: "-o",
25
+ desc: "Output YAML file path (stdout if not specified)"
26
+ method_option :verbose, type: :boolean,
27
+ desc: "Show verbose output"
28
+ def import_eengine(input_xml, schema_name, version)
29
+ ChangesImportEengine.call(input_xml, options[:output], schema_name,
30
+ version, **options)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Commands
5
+ # Command to import eengine comparison XML to EXPRESS Changes YAML
6
+ class ChangesImportEengine < Base
7
+ # Parse XML string and convert to SchemaChange
8
+ #
9
+ # @param xml_content [String] Eengine XML content
10
+ # @param schema_name [String] Schema name
11
+ # @param version [String] Version identifier
12
+ # @param options [Hash] Additional options
13
+ # @return [Expressir::Changes::SchemaChange]
14
+ def self.from_xml(xml_content, schema_name, version, **)
15
+ # Parse into CompareReport using Lutaml::Model
16
+ compare_report = Expressir::Eengine::CompareReport.from_xml(xml_content)
17
+
18
+ # Convert to SchemaChange
19
+ convert_to_schema_change(compare_report, schema_name, version,
20
+ xml_content: xml_content, **)
21
+ end
22
+
23
+ # File-based workflow (backward compatible)
24
+ def self.call(input_file, output_file, schema_name, version, **options)
25
+ xml_content = File.read(input_file)
26
+
27
+ # Load existing schema if output file exists
28
+ existing_schema = if output_file && File.exist?(output_file) && File.size(output_file).positive?
29
+ Expressir::Changes::SchemaChange.from_file(output_file)
30
+ end
31
+
32
+ change_schema = from_xml(xml_content, schema_name, version,
33
+ existing_schema: existing_schema, **options)
34
+
35
+ if output_file
36
+ change_schema.to_file(output_file)
37
+ puts "Change YAML file written to: #{output_file}" if options[:verbose]
38
+ else
39
+ puts change_schema.to_yaml
40
+ end
41
+
42
+ change_schema
43
+ end
44
+
45
+ class << self
46
+ private
47
+
48
+ def convert_to_schema_change(compare_report, schema_name, version,
49
+ **options)
50
+ # Extract changes from CompareReport
51
+ changes = {
52
+ additions: extract_items(compare_report.additions,
53
+ options[:xml_content]),
54
+ modifications: extract_items(compare_report.modifications,
55
+ options[:xml_content]),
56
+ deletions: extract_items(compare_report.deletions,
57
+ options[:xml_content]),
58
+ }
59
+
60
+ # Use existing schema or create new one
61
+ change_schema = options[:existing_schema] ||
62
+ Expressir::Changes::SchemaChange.new(schema: schema_name)
63
+
64
+ # No version-level description from eengine (only item-level)
65
+ change_schema.add_or_update_version(version, nil, changes)
66
+
67
+ change_schema
68
+ end
69
+
70
+ def extract_items(changes_section, xml_content)
71
+ return [] unless changes_section&.modified_objects
72
+
73
+ # Extract descriptions from XML as arrays
74
+ descriptions = extract_descriptions_from_xml(xml_content)
75
+
76
+ changes_section.modified_objects.map do |obj|
77
+ Expressir::Changes::ItemChange.new(
78
+ type: obj.type,
79
+ name: obj.name,
80
+ interfaced_items: obj.interfaced_items,
81
+ description: descriptions[obj.name],
82
+ )
83
+ end
84
+ end
85
+
86
+ def extract_descriptions_from_xml(xml_content)
87
+ return {} unless xml_content
88
+
89
+ require "nokogiri"
90
+ doc = Nokogiri::XML(xml_content)
91
+
92
+ doc.xpath("//modified.object").each_with_object({}) do |node, result|
93
+ name = node["name"]
94
+ desc_node = node.at_xpath("description")
95
+ next unless desc_node
96
+
97
+ html = desc_node.inner_html.strip
98
+ next if html.empty?
99
+
100
+ # Extract <li> elements or use text content
101
+ li_elements = Nokogiri::HTML.fragment(html).css("li")
102
+ result[name] = if li_elements.any?
103
+ li_elements.map do |li|
104
+ li.text.strip
105
+ end.reject(&:empty?)
106
+ else
107
+ [Nokogiri::HTML.fragment(html).text.strip]
108
+ end
109
+ end
110
+ end
111
+
112
+ def normalize_description(description)
113
+ # Handle both String and Array (when XML has nested elements)
114
+ case description
115
+ when String
116
+ description
117
+ when Array
118
+ # Join array elements, handling nested structures
119
+ description.map { |elem| normalize_description(elem) }.join("\n")
120
+ when Hash
121
+ # Handle hash elements (from XML parsing)
122
+ if description.key?("__text__")
123
+ description["__text__"]
124
+ else
125
+ description.values.map { |v| normalize_description(v) }.join("\n")
126
+ end
127
+ else
128
+ description.to_s
129
+ end
130
+ end
131
+
132
+ def convert_html_to_asciidoc(text)
133
+ # Convert <ul><li>...</li></ul> to AsciiDoc list format
134
+ text = text.gsub(%r{<ul>\s*}i, "")
135
+ text = text.gsub(%r{\s*</ul>}i, "")
136
+ text = text.gsub(%r{<li>(.*?)</li>}im) do
137
+ "* #{Regexp.last_match(1).strip}"
138
+ end
139
+
140
+ # Clean up any extra whitespace
141
+ text.strip
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Expressir
4
+ module Commands
5
+ # Command to validate and normalize EXPRESS Changes YAML files
6
+ class ChangesValidate < Base
7
+ def run(path)
8
+ # Check if file exists
9
+ unless File.exist?(path)
10
+ exit_with_error("File not found: #{path}")
11
+ end
12
+
13
+ # Validate --in-place requires --normalize
14
+ if options[:in_place] && !options[:normalize]
15
+ exit_with_error("--in-place requires --normalize flag")
16
+ end
17
+
18
+ # Validate --in-place and --output are mutually exclusive
19
+ if options[:in_place] && options[:output]
20
+ exit_with_error("Cannot use both --in-place and --output")
21
+ end
22
+
23
+ begin
24
+ # Load and validate the file
25
+ say "Validating #{path}..." if options[:verbose]
26
+ schema_change = Expressir::Changes::SchemaChange.from_file(path)
27
+
28
+ say "✓ File is valid" if options[:verbose]
29
+ say " Schema: #{schema_change.schema}" if options[:verbose]
30
+ say " Versions: #{schema_change.versions.length}" if options[:verbose]
31
+
32
+ # Normalize if requested
33
+ if options[:normalize]
34
+ say "Normalizing through round-trip serialization..." if options[:verbose]
35
+
36
+ output_path = if options[:in_place]
37
+ path
38
+ elsif options[:output]
39
+ options[:output]
40
+ else
41
+ # Output to stdout
42
+ nil
43
+ end
44
+
45
+ if output_path
46
+ schema_change.to_file(output_path)
47
+ say "✓ Normalized file written to: #{output_path}"
48
+ else
49
+ # Output to stdout
50
+ puts schema_change.to_yaml
51
+ end
52
+ else
53
+ say "✓ File is valid"
54
+ end
55
+ rescue Psych::SyntaxError => e
56
+ exit_with_error("Invalid YAML syntax: #{e.message}")
57
+ rescue StandardError => e
58
+ exit_with_error("Validation failed: #{e.message}")
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,56 @@
1
+ require "json"
2
+
3
+ module Expressir
4
+ module Commands
5
+ # `validate check` — semantic checks modeled on eeng check-p11 note
6
+ # subset (expressir#282). Exits 1 when any :error notes are emitted.
7
+ # Loads the interface closure of each input file so USE FROM targets
8
+ # are visible — matches Concatenator/Shtolo expectations.
9
+ class Check < Base
10
+ def run(*paths)
11
+ files = Array(paths).flat_map do |p|
12
+ if File.directory?(p)
13
+ Dir["#{p}/**/*.exp"]
14
+ else
15
+ ParityInputs.closure_paths(
16
+ p, manifest: options[:manifest], stepmod: options[:stepmod]
17
+ ).select { |f| File.exist?(f) }
18
+ end
19
+ end.uniq
20
+ repository = Expressir::Express::Parser.from_files(files)
21
+ # A file that failed to parse is a nil entry: it must fail the run,
22
+ # not pass silently as a "clean" schema (#413).
23
+ failed = repository.files.count(&:nil?)
24
+ if failed.positive?
25
+ raise Thor::Error, "#{failed} file(s) failed to parse"
26
+ end
27
+
28
+ result = Expressir::Express::Checker.new(repository).check
29
+
30
+ if options[:json]
31
+ say JSON.generate(
32
+ valid: result.valid?,
33
+ errors: serialize(result.errors),
34
+ warnings: serialize(result.warnings),
35
+ )
36
+ else
37
+ result.notes.each { |n| say "[#{n.severity}] #{n.id}: #{n.message}" }
38
+ say "#{result.errors.size} error(s), #{result.warnings.size} warning(s)"
39
+ end
40
+
41
+ return if result.valid?
42
+
43
+ raise Thor::Error, "schema check produced #{result.errors.size} error(s)"
44
+ end
45
+
46
+ private
47
+
48
+ def serialize(notes)
49
+ notes.map do |n|
50
+ { id: n.id.to_s, severity: n.severity.to_s, schema: n.schema,
51
+ message: n.message }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,20 @@
1
+ module Expressir
2
+ module Commands
3
+ class Clean < Base
4
+ def run(path)
5
+ repository = Expressir::Express::Parser.from_file(path)
6
+ formatted_schemas = repository.schemas.map do |schema|
7
+ # Format schema without remarks
8
+ schema.format(no_remarks: true)
9
+ end.join("\n\n")
10
+
11
+ if options[:output]
12
+ File.write(options[:output], formatted_schemas)
13
+ say "Cleaned schema written to #{options[:output]}"
14
+ else
15
+ say formatted_schemas
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end