From 492bc7c3d757f06ac246a61f6f27e19702ad08a5 Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Thu, 14 May 2026 07:16:28 +0800 Subject: [PATCH 1/2] feat: add XSD direct block syntax and extract build_file_system Add lutaml_xsd::path[context, template, options] direct block syntax to LutamlXsdPreprocessor, enabling external Liquid template files for XSD schema rendering. Extract FILE_SYSTEM_PATTERNS constant and build_file_system method into BasePreprocessor for reuse by both block and direct syntax paths. Enable rubygems MFA requirement in gemspec. --- .gitignore | 3 + .rubocop_todo.yml | 100 +- Gemfile | 1 - .../plugin/lutaml/base_preprocessor.rb | 22 +- .../plugin/lutaml/lutaml_xsd_preprocessor.rb | 54 + metanorma-plugin-lutaml.gemspec | 2 +- .../_attribute_groups.adoc | 11 + .../_complex_type.adoc | 11 + .../unitsml_liquid_templates/_elements.adoc | 5 + .../unitsml_liquid_templates/schema.adoc | 11 + spec/fixtures/lutaml/xsd_schemas/omml.xsd | 1534 +++++++++++++++++ .../lutaml/xsd_schemas/unitsml-v1.0-csd04.xsd | 1335 ++++++++++++++ spec/fixtures/lutaml/xsd_schemas/wml.xsd | 19 + 13 files changed, 3047 insertions(+), 61 deletions(-) create mode 100644 spec/fixtures/lutaml/unitsml_liquid_templates/_attribute_groups.adoc create mode 100644 spec/fixtures/lutaml/unitsml_liquid_templates/_complex_type.adoc create mode 100644 spec/fixtures/lutaml/unitsml_liquid_templates/_elements.adoc create mode 100644 spec/fixtures/lutaml/unitsml_liquid_templates/schema.adoc create mode 100644 spec/fixtures/lutaml/xsd_schemas/omml.xsd create mode 100644 spec/fixtures/lutaml/xsd_schemas/unitsml-v1.0-csd04.xsd create mode 100644 spec/fixtures/lutaml/xsd_schemas/wml.xsd diff --git a/.gitignore b/.gitignore index 7d1e5bdc..37f46b04 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ Gemfile.lock .rspec_status spec/assets/lutaml test.err +test.err.html +TODO.cleanup/ +pkg/ .rubocop-https--* .DS_Store diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b10dde28..06ea17b9 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2026-05-12 14:53:16 UTC using RuboCop version 1.86.1. +# on 2026-05-13 23:15:25 UTC using RuboCop version 1.86.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -12,75 +12,67 @@ Gemspec/RequireMFA: Exclude: - 'metanorma-plugin-lutaml.gemspec' -# Offense count: 1 +# Offense count: 4 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle, IndentationWidth. # SupportedStyles: with_first_argument, with_fixed_indentation Layout/ArgumentAlignment: Exclude: - - 'lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb' + - 'spec/regen_expected.rb' + - 'spec/regen_expected_spec.rb' # Offense count: 1 # This cop supports safe autocorrection (--autocorrect). -Layout/ClosingParenthesisIndentation: +# Configuration parameters: IndentationWidth. +Layout/AssignmentIndentation: Exclude: - - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' + - 'lib/metanorma/plugin/lutaml/base_preprocessor.rb' -# Offense count: 1 +# Offense count: 2 # This cop supports safe autocorrection (--autocorrect). Layout/EmptyLines: Exclude: - - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' - -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses -Layout/FirstArgumentIndentation: - Exclude: - - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' + - 'spec/regen_expected.rb' -# Offense count: 9 +# Offense count: 12 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings. # URISchemes: http, https Layout/LineLength: Exclude: - 'Rakefile' + - 'lib/metanorma/plugin/lutaml/base_preprocessor.rb' - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' - - 'lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb' - 'lib/metanorma/plugin/lutaml/utils.rb' - 'spec/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor_spec.rb' + - 'spec/metanorma/plugin/lutaml/lutaml_xsd_preprocessor_spec.rb' + - 'spec/regen_expected.rb' + - 'spec/regen_expected_spec.rb' - 'spec/support/shared_examples/structured_data_2_text_preprocessor.rb' -# Offense count: 1 +# Offense count: 2 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle. -# SupportedStyles: symmetrical, new_line, same_line -Layout/MultilineMethodCallBraceLayout: +# SupportedStyles: final_newline, final_blank_line +Layout/TrailingEmptyLines: Exclude: - - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' + - 'Gemfile' + - 'spec/regen_expected.rb' -# Offense count: 3 +# Offense count: 5 # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowInHeredoc. Layout/TrailingWhitespace: Exclude: - - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' - - 'lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb' + - 'lib/metanorma/plugin/lutaml/base_preprocessor.rb' + - 'spec/regen_expected.rb' + - 'spec/regen_expected_spec.rb' -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions. -# NotImplementedExceptions: NotImplementedError -Lint/UnusedMethodArgument: - Exclude: - - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' - -# Offense count: 1 +# Offense count: 2 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max. Metrics/AbcSize: Exclude: + - 'lib/metanorma/plugin/lutaml/lutaml_xsd_preprocessor.rb' - 'lib/metanorma/plugin/lutaml/utils.rb' # Offense count: 2 @@ -90,7 +82,7 @@ Metrics/CyclomaticComplexity: - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' - 'lib/metanorma/plugin/lutaml/utils.rb' -# Offense count: 3 +# Offense count: 7 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: Max: 19 @@ -118,12 +110,6 @@ Naming/PredicateMethod: - 'lib/metanorma/plugin/lutaml/asciidoctor/preprocessor.rb' - 'lib/metanorma/plugin/lutaml/liquid/custom_filters/file_exist.rb' -# Offense count: 1 -# This cop supports unsafe autocorrection (--autocorrect-all). -Performance/AncestorsInclude: - Exclude: - - 'lib/metanorma/plugin/lutaml/utils.rb' - # Offense count: 86 # Configuration parameters: Prefixes, AllowedPatterns. # Prefixes: when, with, without @@ -141,10 +127,16 @@ RSpec/ContextWording: - 'spec/metanorma/plugin/lutaml/macros_data2text_spec.rb' - 'spec/support/shared_examples/structured_data_2_text_preprocessor.rb' -# Offense count: 37 +# Offense count: 1 +# Configuration parameters: IgnoredMetadata. +RSpec/DescribeClass: + Exclude: + - 'spec/regen_expected_spec.rb' + +# Offense count: 40 # Configuration parameters: CountAsOne. RSpec/ExampleLength: - Max: 26 + Max: 38 # Offense count: 13 # Configuration parameters: Max, AllowedIdentifiers, AllowedPatterns. @@ -169,11 +161,11 @@ RSpec/LeakyLocalVariable: - 'spec/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor_spec.rb' - 'spec/metanorma/plugin/lutaml/lutaml_xmi_index_spec.rb' -# Offense count: 14 +# Offense count: 16 RSpec/MultipleExpectations: Max: 6 -# Offense count: 9 +# Offense count: 15 # Configuration parameters: AllowSubject. RSpec/MultipleMemoizedHelpers: Max: 8 @@ -191,11 +183,17 @@ RSpec/NamedSubject: - 'spec/metanorma/plugin/lutaml/lutaml_xmi_index_spec.rb' - 'spec/metanorma/plugin/lutaml/source_extractor_spec.rb' -# Offense count: 117 +# Offense count: 124 # Configuration parameters: AllowedGroups. RSpec/NestedGroups: Max: 7 +# Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). +RSpec/Output: + Exclude: + - 'spec/regen_expected.rb' + # Offense count: 1 RSpec/PendingWithoutReason: Exclude: @@ -225,14 +223,16 @@ RSpec/SubjectDeclaration: # Offense count: 1 # This cop supports safe autocorrection (--autocorrect). -Style/RedundantBegin: +# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. +# SupportedStyles: single_quotes, double_quotes +Style/StringLiterals: Exclude: - - 'lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb' + - 'metanorma-plugin-lutaml.gemspec' # Offense count: 1 # This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. +# Configuration parameters: EnforcedStyle. # SupportedStyles: single_quotes, double_quotes -Style/StringLiterals: +Style/StringLiteralsInInterpolation: Exclude: - - 'metanorma-plugin-lutaml.gemspec' + - 'spec/metanorma/plugin/lutaml/lutaml_xsd_preprocessor_spec.rb' diff --git a/Gemfile b/Gemfile index 202a0e17..87c88517 100644 --- a/Gemfile +++ b/Gemfile @@ -28,4 +28,3 @@ gem "simplecov" gem "timecop" gem "vcr" gem "webmock" - diff --git a/lib/metanorma/plugin/lutaml/base_preprocessor.rb b/lib/metanorma/plugin/lutaml/base_preprocessor.rb index 8ea9f05c..bcf2e4ff 100644 --- a/lib/metanorma/plugin/lutaml/base_preprocessor.rb +++ b/lib/metanorma/plugin/lutaml/base_preprocessor.rb @@ -24,6 +24,8 @@ module Lutaml class BasePreprocessor < ::Asciidoctor::Extensions::Preprocessor include Utils + FILE_SYSTEM_PATTERNS = ["%s.liquid", "_%s.liquid", "_%s.adoc"].freeze + def process(document, reader) input_lines = Asciidoctor::PreprocessorNoIfdefsReader .new(document, reader.lines).readlines.to_enum @@ -75,6 +77,15 @@ def index_missing_message(path) "please specify the full path." end + def build_file_system(document, options) + include_paths = [Utils.relative_file_path(document, "")] + options["include_path"]&.split(",")&.each do |path| + include_paths.push(Utils.relative_file_path(document, path)) + end + ::Metanorma::Plugin::Lutaml::Liquid::LocalFileSystem + .new(include_paths, FILE_SYSTEM_PATTERNS) + end + private def process_input_lines(document:, input_lines:, express_indexes:) @@ -151,16 +162,9 @@ def render_liquid_template(document:, lines:, context_name:, # rubocop:disable M options: options.merge("document" => document) ) - include_paths = [Utils.relative_file_path(document, "")] - options["include_path"]&.split(",")&.each do |path| - include_paths.push(Utils.relative_file_path(document, path)) - end - - file_system = ::Metanorma::Plugin::Lutaml::Liquid::LocalFileSystem - .new(include_paths, ["%s.liquid", "_%s.liquid", "_%s.adoc"]) - parsed_template = template(lines) - parsed_template.registers[:file_system] = file_system + parsed_template.registers[:file_system] = + build_file_system(document, options) all_items.map do |item| parsed_template.assigns[context_name] = item[:liquid_drop] diff --git a/lib/metanorma/plugin/lutaml/lutaml_xsd_preprocessor.rb b/lib/metanorma/plugin/lutaml/lutaml_xsd_preprocessor.rb index eb8e97a2..9034786b 100644 --- a/lib/metanorma/plugin/lutaml/lutaml_xsd_preprocessor.rb +++ b/lib/metanorma/plugin/lutaml/lutaml_xsd_preprocessor.rb @@ -9,6 +9,10 @@ module Lutaml # lutaml-model's XSD parser and exposes the schema object to Liquid # templates. # + # Two syntaxes are supported: + # Block: [lutaml_xsd, path, context, options] .... ---- + # Direct: lutaml_xsd::path[context, template, options] + # # Caching: parsed XSD results are cached at two levels: # - Class-level (@@xsd_cache) persists across document invocations # - Document-level (document.attributes["lutaml_xsd_cache"]) within a @@ -26,6 +30,19 @@ class LutamlXsdPreprocessor < BasePreprocessor \] # Closing bracket }x + XSD_DIRECT_REGEX = %r{ + ^\s* # Start of line + lutaml_xsd:: # Macro prefix + (?[^\[]+?) # XSD file path + \[ # Opening bracket + (?[^,]+) # Context name + ,\s* # Comma separator + (?