canon 0.2.11 → 0.2.12
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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +12 -22
- data/Rakefile +5 -2
- data/lib/canon/cache.rb +3 -1
- data/lib/canon/cli.rb +0 -3
- data/lib/canon/commands/diff_command.rb +0 -6
- data/lib/canon/commands/format_command.rb +0 -4
- data/lib/canon/commands.rb +9 -0
- data/lib/canon/comparison/child_realignment.rb +0 -2
- data/lib/canon/comparison/compare_profile.rb +30 -36
- data/lib/canon/comparison/comparison_result.rb +0 -2
- data/lib/canon/comparison/diff_node_builder.rb +353 -0
- data/lib/canon/comparison/dimensions/dimension.rb +51 -0
- data/lib/canon/comparison/dimensions/dimension_set.rb +49 -0
- data/lib/canon/comparison/dimensions/registry.rb +101 -60
- data/lib/canon/comparison/dimensions.rb +15 -46
- data/lib/canon/comparison/html_comparator.rb +18 -141
- data/lib/canon/comparison/html_compare_profile.rb +15 -18
- data/lib/canon/comparison/json_comparator.rb +4 -165
- data/lib/canon/comparison/json_parser.rb +0 -2
- data/lib/canon/comparison/markup_comparator.rb +14 -210
- data/lib/canon/comparison/match_options/base_resolver.rb +18 -29
- data/lib/canon/comparison/match_options/json_resolver.rb +4 -28
- data/lib/canon/comparison/match_options/xml_resolver.rb +4 -45
- data/lib/canon/comparison/match_options/yaml_resolver.rb +4 -30
- data/lib/canon/comparison/match_options.rb +13 -88
- data/lib/canon/comparison/pipeline.rb +269 -0
- data/lib/canon/comparison/profile_definition.rb +0 -2
- data/lib/canon/comparison/ruby_object_comparator.rb +1 -1
- data/lib/canon/comparison/strategies/match_strategy_factory.rb +9 -58
- data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +4 -11
- data/lib/canon/comparison/strategies.rb +16 -0
- data/lib/canon/comparison/xml_comparator/attribute_comparator.rb +0 -3
- data/lib/canon/comparison/xml_comparator/attribute_filter.rb +0 -3
- data/lib/canon/comparison/xml_comparator/child_comparison.rb +0 -6
- data/lib/canon/comparison/xml_comparator/namespace_comparator.rb +1 -6
- data/lib/canon/comparison/xml_comparator/node_parser.rb +0 -4
- data/lib/canon/comparison/xml_comparator.rb +4 -492
- data/lib/canon/comparison/xml_comparator_helpers.rb +21 -0
- data/lib/canon/comparison/xml_node_comparison.rb +4 -119
- data/lib/canon/comparison/yaml_comparator.rb +0 -3
- data/lib/canon/comparison.rb +143 -266
- data/lib/canon/config/config_dsl.rb +159 -0
- data/lib/canon/config/env_provider.rb +0 -3
- data/lib/canon/config/env_schema.rb +48 -58
- data/lib/canon/config/profile_loader.rb +0 -1
- data/lib/canon/config.rb +116 -468
- data/lib/canon/diff/diff_block_builder.rb +0 -2
- data/lib/canon/diff/diff_classifier.rb +0 -5
- data/lib/canon/diff/diff_context.rb +0 -2
- data/lib/canon/diff/diff_context_builder.rb +0 -2
- data/lib/canon/diff/diff_line_builder.rb +0 -3
- data/lib/canon/diff/diff_node_enricher.rb +0 -4
- data/lib/canon/diff/diff_node_mapper.rb +0 -4
- data/lib/canon/diff/diff_report_builder.rb +0 -4
- data/lib/canon/diff/formatting_detector.rb +0 -1
- data/lib/canon/diff/node_serializer.rb +0 -7
- data/lib/canon/diff.rb +39 -0
- data/lib/canon/diff_formatter/by_line/base_formatter.rb +4 -17
- data/lib/canon/diff_formatter/by_line/html_formatter.rb +7 -19
- data/lib/canon/diff_formatter/by_line/json_formatter.rb +0 -3
- data/lib/canon/diff_formatter/by_line/simple_formatter.rb +0 -3
- data/lib/canon/diff_formatter/by_line/xml_formatter.rb +7 -26
- data/lib/canon/diff_formatter/by_line/yaml_formatter.rb +0 -3
- data/lib/canon/diff_formatter/by_object/base_formatter.rb +8 -15
- data/lib/canon/diff_formatter/by_object/json_formatter.rb +0 -2
- data/lib/canon/diff_formatter/by_object/xml_formatter.rb +0 -2
- data/lib/canon/diff_formatter/by_object/yaml_formatter.rb +0 -2
- data/lib/canon/diff_formatter/debug_output.rb +0 -2
- data/lib/canon/diff_formatter/diff_detail_formatter/dimension_formatter.rb +24 -58
- data/lib/canon/diff_formatter/diff_detail_formatter/location_extractor.rb +0 -2
- data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +1 -2
- data/lib/canon/diff_formatter/diff_detail_formatter/text_utils.rb +1 -7
- data/lib/canon/diff_formatter/diff_detail_formatter.rb +0 -7
- data/lib/canon/diff_formatter/diff_detail_formatter_helpers.rb +23 -0
- data/lib/canon/diff_formatter.rb +11 -9
- data/lib/canon/formatters/html4_formatter.rb +0 -2
- data/lib/canon/formatters/html5_formatter.rb +0 -2
- data/lib/canon/formatters/html_formatter.rb +0 -3
- data/lib/canon/formatters/json_formatter.rb +0 -1
- data/lib/canon/formatters/xml_formatter.rb +0 -4
- data/lib/canon/formatters/yaml_formatter.rb +0 -1
- data/lib/canon/formatters.rb +16 -0
- data/lib/canon/html/data_model.rb +0 -10
- data/lib/canon/html.rb +4 -3
- data/lib/canon/options/cli_generator.rb +0 -2
- data/lib/canon/options/registry.rb +0 -2
- data/lib/canon/options.rb +9 -0
- data/lib/canon/pretty_printer/html.rb +0 -1
- data/lib/canon/pretty_printer/xml_normalized.rb +0 -2
- data/lib/canon/pretty_printer.rb +12 -0
- data/lib/canon/tree_diff/adapters/html_adapter.rb +1 -1
- data/lib/canon/tree_diff/adapters.rb +14 -0
- data/lib/canon/tree_diff/core/attribute_comparator.rb +0 -6
- data/lib/canon/tree_diff/core/node_signature.rb +1 -1
- data/lib/canon/tree_diff/core/tree_node.rb +12 -5
- data/lib/canon/tree_diff/core.rb +17 -0
- data/lib/canon/tree_diff/matchers/hash_matcher.rb +0 -7
- data/lib/canon/tree_diff/matchers/similarity_matcher.rb +1 -5
- data/lib/canon/tree_diff/matchers/structural_propagator.rb +1 -5
- data/lib/canon/tree_diff/matchers.rb +15 -0
- data/lib/canon/tree_diff/operation_converter.rb +0 -8
- data/lib/canon/tree_diff/operation_converter_helpers/metadata_enricher.rb +2 -12
- data/lib/canon/tree_diff/operation_converter_helpers/post_processor.rb +13 -7
- data/lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb +2 -2
- data/lib/canon/tree_diff/operation_converter_helpers/update_change_handler.rb +4 -6
- data/lib/canon/tree_diff/operation_converter_helpers.rb +18 -0
- data/lib/canon/tree_diff/operations/operation_detector.rb +2 -5
- data/lib/canon/tree_diff/operations.rb +13 -0
- data/lib/canon/tree_diff.rb +26 -27
- data/lib/canon/validators/base_validator.rb +0 -2
- data/lib/canon/validators/html_validator.rb +0 -1
- data/lib/canon/validators/json_validator.rb +0 -1
- data/lib/canon/validators/xml_validator.rb +0 -1
- data/lib/canon/validators/yaml_validator.rb +0 -1
- data/lib/canon/validators.rb +12 -0
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml/c14n.rb +0 -4
- data/lib/canon/xml/data_model.rb +0 -10
- data/lib/canon/xml/line_range_mapper.rb +0 -2
- data/lib/canon/xml/nodes/attribute_node.rb +0 -2
- data/lib/canon/xml/nodes/comment_node.rb +0 -2
- data/lib/canon/xml/nodes/element_node.rb +0 -2
- data/lib/canon/xml/nodes/namespace_node.rb +0 -2
- data/lib/canon/xml/nodes/processing_instruction_node.rb +0 -2
- data/lib/canon/xml/nodes/root_node.rb +0 -2
- data/lib/canon/xml/nodes/text_node.rb +0 -2
- data/lib/canon/xml/nodes.rb +19 -0
- data/lib/canon/xml/processor.rb +0 -5
- data/lib/canon/xml/sax_builder.rb +0 -7
- data/lib/canon/xml.rb +33 -0
- data/lib/canon/xml_backend.rb +50 -14
- data/lib/canon/xml_parsing.rb +4 -2
- data/lib/canon.rb +25 -15
- data/lib/tasks/performance.rake +0 -58
- data/lib/tasks/performance_comparator.rb +132 -65
- data/lib/tasks/performance_helpers.rb +4 -249
- data/lib/tasks/performance_report.rb +309 -0
- metadata +24 -11
- data/lib/canon/comparison/dimensions/attribute_order_dimension.rb +0 -64
- data/lib/canon/comparison/dimensions/attribute_presence_dimension.rb +0 -64
- data/lib/canon/comparison/dimensions/attribute_values_dimension.rb +0 -167
- data/lib/canon/comparison/dimensions/base_dimension.rb +0 -107
- data/lib/canon/comparison/dimensions/comments_dimension.rb +0 -117
- data/lib/canon/comparison/dimensions/element_position_dimension.rb +0 -86
- data/lib/canon/comparison/dimensions/structural_whitespace_dimension.rb +0 -115
- data/lib/canon/comparison/dimensions/text_content_dimension.rb +0 -102
- data/lib/canon/comparison/xml_comparator/diff_node_builder.rb +0 -300
data/lib/canon/config.rb
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "config/env_provider"
|
|
4
|
-
require_relative "config/override_resolver"
|
|
5
|
-
require_relative "config/profile_loader"
|
|
6
|
-
require_relative "color_detector"
|
|
7
|
-
|
|
8
3
|
module Canon
|
|
9
4
|
# Global configuration for Canon
|
|
10
5
|
# Provides unified configuration across CLI, Ruby API, and RSpec interfaces
|
|
11
6
|
class Config
|
|
7
|
+
autoload :ConfigDSL, "canon/config/config_dsl"
|
|
8
|
+
autoload :EnvProvider, "canon/config/env_provider"
|
|
9
|
+
autoload :EnvSchema, "canon/config/env_schema"
|
|
10
|
+
autoload :OverrideResolver, "canon/config/override_resolver"
|
|
11
|
+
autoload :ProfileLoader, "canon/config/profile_loader"
|
|
12
|
+
autoload :TypeConverter, "canon/config/type_converter"
|
|
13
|
+
|
|
12
14
|
class << self
|
|
13
15
|
def instance
|
|
14
16
|
@instance ||= new
|
|
@@ -295,22 +297,16 @@ module Canon
|
|
|
295
297
|
end
|
|
296
298
|
|
|
297
299
|
# Diff configuration for output formatting
|
|
300
|
+
#
|
|
301
|
+
# Each user-tunable attribute is declared with +config_key+ via the
|
|
302
|
+
# +ConfigDSL+ module. The DSL generates the matching getter/setter
|
|
303
|
+
# pair and registers metadata (type, enum, default) so +EnvSchema+
|
|
304
|
+
# and +TypeConverter+ can discover it without re-declaring it
|
|
305
|
+
# (lutaml/canon TODO.improve/07 — single source of truth).
|
|
298
306
|
class DiffConfig
|
|
299
|
-
|
|
307
|
+
extend ConfigDSL
|
|
300
308
|
|
|
301
|
-
|
|
302
|
-
VALID_ENUM_VALUES = {
|
|
303
|
-
mode: %i[by_line by_object pretty_diff],
|
|
304
|
-
show_diffs: %i[all normative informative],
|
|
305
|
-
algorithm: %i[dom semantic],
|
|
306
|
-
parser: %i[sax dom],
|
|
307
|
-
display_preprocessing: %i[none pretty_print normalize_pretty_print
|
|
308
|
-
c14n],
|
|
309
|
-
display_format: %i[raw canonical],
|
|
310
|
-
pretty_printer_indent_type: %i[space tab],
|
|
311
|
-
character_visualization: [true, false, :content_only],
|
|
312
|
-
theme: %i[light dark retro claude cyberpunk],
|
|
313
|
-
}.freeze
|
|
309
|
+
attr_reader :pretty_printer
|
|
314
310
|
|
|
315
311
|
def initialize(format = nil)
|
|
316
312
|
@format = format
|
|
@@ -338,416 +334,104 @@ module Canon
|
|
|
338
334
|
@resolver.clear_profile!
|
|
339
335
|
end
|
|
340
336
|
|
|
341
|
-
#
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
#
|
|
428
|
-
#
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
end
|
|
440
|
-
|
|
441
|
-
def show_preprocessed_inputs
|
|
442
|
-
@resolver.resolve(:show_preprocessed_inputs)
|
|
443
|
-
end
|
|
444
|
-
|
|
445
|
-
def show_preprocessed_inputs=(value)
|
|
446
|
-
@resolver.set_programmatic(:show_preprocessed_inputs, value)
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
# Show only the EXPECTED (fixture) block in the preprocessed-inputs
|
|
450
|
-
# section. Has no effect unless +show_preprocessed_inputs+ or
|
|
451
|
-
# +verbose_diff+ is also set. Use +show_preprocessed_expected: true+
|
|
452
|
-
# together with +show_preprocessed_received: false+ to display only the
|
|
453
|
-
# preprocessed fixture while suppressing the preprocessed received output.
|
|
454
|
-
#
|
|
455
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_SHOW_PREPROCESSED_EXPECTED+
|
|
456
|
-
def show_preprocessed_expected
|
|
457
|
-
@resolver.resolve(:show_preprocessed_expected)
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
def show_preprocessed_expected=(value)
|
|
461
|
-
@resolver.set_programmatic(:show_preprocessed_expected, value)
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
# Show only the RECEIVED (actual) block in the preprocessed-inputs
|
|
465
|
-
# section. Combined with +show_preprocessed_expected: false+ (or leaving
|
|
466
|
-
# it at the default +false+) this suppresses the fixture preprocessing
|
|
467
|
-
# display while still showing what the received document looked like after
|
|
468
|
-
# preprocessing.
|
|
469
|
-
#
|
|
470
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_SHOW_PREPROCESSED_RECEIVED+
|
|
471
|
-
def show_preprocessed_received
|
|
472
|
-
@resolver.resolve(:show_preprocessed_received)
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
def show_preprocessed_received=(value)
|
|
476
|
-
@resolver.set_programmatic(:show_preprocessed_received, value)
|
|
477
|
-
end
|
|
478
|
-
|
|
479
|
-
# Show both EXPECTED and RECEIVED blocks in a fixture-ready pretty-printed
|
|
480
|
-
# section. The output uses the same pretty-printer as
|
|
481
|
-
# +display_preprocessing: :pretty_print+ (one tag per line, indentation)
|
|
482
|
-
# but with *no* character visualization — whitespace appears as plain ASCII
|
|
483
|
-
# so the output can be copy-pasted directly into RSpec fixture heredocs.
|
|
484
|
-
#
|
|
485
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_SHOW_PRETTYPRINT_INPUTS+
|
|
486
|
-
def show_prettyprint_inputs
|
|
487
|
-
@resolver.resolve(:show_prettyprint_inputs)
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
def show_prettyprint_inputs=(value)
|
|
491
|
-
@resolver.set_programmatic(:show_prettyprint_inputs, value)
|
|
492
|
-
end
|
|
493
|
-
|
|
494
|
-
# Show only the EXPECTED (fixture) block in the pretty-print section.
|
|
495
|
-
# Useful when the fixture is what needs updating and the received side is
|
|
496
|
-
# not needed for copy-pasting.
|
|
497
|
-
#
|
|
498
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_SHOW_PRETTYPRINT_EXPECTED+
|
|
499
|
-
def show_prettyprint_expected
|
|
500
|
-
@resolver.resolve(:show_prettyprint_expected)
|
|
501
|
-
end
|
|
502
|
-
|
|
503
|
-
def show_prettyprint_expected=(value)
|
|
504
|
-
@resolver.set_programmatic(:show_prettyprint_expected, value)
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
# Show only the RECEIVED (actual) block in the pretty-print section.
|
|
508
|
-
# Use this to get a copy-pasteable pretty-printed form of the generated
|
|
509
|
-
# output (the most common fixture-update workflow).
|
|
510
|
-
#
|
|
511
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_SHOW_PRETTYPRINT_RECEIVED+
|
|
512
|
-
def show_prettyprint_received
|
|
513
|
-
@resolver.resolve(:show_prettyprint_received)
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
def show_prettyprint_received=(value)
|
|
517
|
-
@resolver.set_programmatic(:show_prettyprint_received, value)
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
def show_line_numbered_inputs
|
|
521
|
-
@resolver.resolve(:show_line_numbered_inputs)
|
|
522
|
-
end
|
|
523
|
-
|
|
524
|
-
def show_line_numbered_inputs=(value)
|
|
525
|
-
@resolver.set_programmatic(:show_line_numbered_inputs, value)
|
|
526
|
-
end
|
|
527
|
-
|
|
528
|
-
def display_format
|
|
529
|
-
@resolver.resolve(:display_format)
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
def display_format=(value)
|
|
533
|
-
self.class.validate_config_value!(:display_format, value)
|
|
534
|
-
@resolver.set_programmatic(:display_format, value)
|
|
535
|
-
end
|
|
536
|
-
|
|
537
|
-
# Controls how documents are normalized *for display* before the line
|
|
538
|
-
# diff. This is independent of +FormatConfig#preprocessing+, which
|
|
539
|
-
# controls normalization for *comparison* (equivalence detection).
|
|
540
|
-
#
|
|
541
|
-
# Values:
|
|
542
|
-
# :none - use documents as-is (default, existing behaviour)
|
|
543
|
-
# :pretty_print - run through Canon::PrettyPrinter::Xml before diffing
|
|
544
|
-
# :c14n - run through XML C14N normalization before diffing
|
|
545
|
-
def display_preprocessing
|
|
546
|
-
@resolver.resolve(:display_preprocessing)
|
|
547
|
-
end
|
|
548
|
-
|
|
549
|
-
def display_preprocessing=(value)
|
|
550
|
-
self.class.validate_config_value!(:display_preprocessing, value)
|
|
551
|
-
@resolver.set_programmatic(:display_preprocessing, value)
|
|
552
|
-
end
|
|
553
|
-
|
|
554
|
-
# Element names where whitespace is PRESERVED exactly (no manipulation).
|
|
555
|
-
# All whitespace characters are significant in these elements.
|
|
556
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_PRESERVE_WHITESPACE_ELEMENTS+
|
|
557
|
-
def preserve_whitespace_elements
|
|
558
|
-
@resolver.resolve(:preserve_whitespace_elements) || []
|
|
559
|
-
end
|
|
560
|
-
|
|
561
|
-
def preserve_whitespace_elements=(value)
|
|
562
|
-
@resolver.set_programmatic(:preserve_whitespace_elements,
|
|
563
|
-
Array(value).map(&:to_s))
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
# Element names where whitespace is COLLAPSED (HTML-style behavior).
|
|
567
|
-
# Multiple whitespace chars collapse to single space; boundaries preserved.
|
|
568
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_COLLAPSE_WHITESPACE_ELEMENTS+
|
|
569
|
-
def collapse_whitespace_elements
|
|
570
|
-
@resolver.resolve(:collapse_whitespace_elements) || []
|
|
571
|
-
end
|
|
572
|
-
|
|
573
|
-
def collapse_whitespace_elements=(value)
|
|
574
|
-
@resolver.set_programmatic(:collapse_whitespace_elements,
|
|
575
|
-
Array(value).map(&:to_s))
|
|
576
|
-
end
|
|
577
|
-
|
|
578
|
-
# Element names where whitespace-only text nodes are STRIPPED.
|
|
579
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_STRIP_WHITESPACE_ELEMENTS+
|
|
580
|
-
def strip_whitespace_elements
|
|
581
|
-
@resolver.resolve(:strip_whitespace_elements) || []
|
|
582
|
-
end
|
|
583
|
-
|
|
584
|
-
def strip_whitespace_elements=(value)
|
|
585
|
-
@resolver.set_programmatic(:strip_whitespace_elements,
|
|
586
|
-
Array(value).map(&:to_s))
|
|
587
|
-
end
|
|
588
|
-
|
|
589
|
-
# When true, whitespace-only text nodes starting with "\n" in :collapse
|
|
590
|
-
# elements of the **expected** (fixture) document are treated as structural
|
|
591
|
-
# indentation and dropped from both comparison and display. Use this when
|
|
592
|
-
# fixture files are indented but received XML is compact.
|
|
593
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_PRETTY_PRINTED_EXPECTED+
|
|
594
|
-
def pretty_printed_expected
|
|
595
|
-
@resolver.resolve(:pretty_printed_expected)
|
|
596
|
-
end
|
|
597
|
-
|
|
598
|
-
def pretty_printed_expected=(value)
|
|
599
|
-
@resolver.set_programmatic(:pretty_printed_expected, value)
|
|
600
|
-
end
|
|
601
|
-
|
|
602
|
-
# When true, whitespace-only text nodes starting with "\n" in :normalize
|
|
603
|
-
# elements of the **received** document are treated as structural
|
|
604
|
-
# indentation and dropped from both comparison and display. Use this when
|
|
605
|
-
# received XML may be pretty-printed but the fixture is compact.
|
|
606
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_PRETTY_PRINTED_RECEIVED+
|
|
607
|
-
def pretty_printed_received
|
|
608
|
-
@resolver.resolve(:pretty_printed_received)
|
|
609
|
-
end
|
|
610
|
-
|
|
611
|
-
def pretty_printed_received=(value)
|
|
612
|
-
@resolver.set_programmatic(:pretty_printed_received, value)
|
|
613
|
-
end
|
|
614
|
-
|
|
615
|
-
# When true, attributes on each element are sorted by namespace URI
|
|
616
|
-
# then local name in the pretty-printed display, eliminating spurious
|
|
617
|
-
# diff noise from differing attribute order.
|
|
618
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_PRETTY_PRINTER_SORT_ATTRIBUTES+
|
|
619
|
-
def pretty_printer_sort_attributes
|
|
620
|
-
@resolver.resolve(:pretty_printer_sort_attributes)
|
|
621
|
-
end
|
|
622
|
-
|
|
623
|
-
def pretty_printer_sort_attributes=(value)
|
|
624
|
-
@resolver.set_programmatic(:pretty_printer_sort_attributes, value)
|
|
625
|
-
end
|
|
626
|
-
|
|
627
|
-
# Render element nodes in the Semantic Diff Report as compact inline XML
|
|
628
|
-
# (e.g. +<strong>Annex</strong>+) instead of the verbose node_info
|
|
629
|
-
# description string (e.g. "name: strong namespace_uri: …").
|
|
630
|
-
#
|
|
631
|
-
# Default: +false+ (keep existing verbose format for backwards compatibility)
|
|
632
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_COMPACT_SEMANTIC_REPORT+
|
|
633
|
-
def compact_semantic_report
|
|
634
|
-
@resolver.resolve(:compact_semantic_report)
|
|
635
|
-
end
|
|
636
|
-
|
|
637
|
-
def compact_semantic_report=(value)
|
|
638
|
-
@resolver.set_programmatic(:compact_semantic_report, value)
|
|
639
|
-
end
|
|
640
|
-
|
|
641
|
-
# Show the full serialized node content (including children) in
|
|
642
|
-
# element_structure diffs instead of just the tag name.
|
|
643
|
-
#
|
|
644
|
-
# Default: +false+ (show only the tag name, e.g. +<biblio-tag>+)
|
|
645
|
-
# ENV variable: +CANON_<FORMAT>_DIFF_EXPAND_DIFFERENCE+
|
|
646
|
-
def expand_difference
|
|
647
|
-
@resolver.resolve(:expand_difference)
|
|
648
|
-
end
|
|
649
|
-
|
|
650
|
-
def expand_difference=(value)
|
|
651
|
-
@resolver.set_programmatic(:expand_difference, value)
|
|
652
|
-
end
|
|
653
|
-
|
|
654
|
-
# Controls whether invisible characters (spaces, tabs, non-breaking
|
|
655
|
-
# spaces, etc.) are replaced with visible Unicode symbols in diff output.
|
|
656
|
-
#
|
|
657
|
-
# Values:
|
|
658
|
-
# true - apply the full default visualization map (default)
|
|
659
|
-
# false - disable visualization; output plain text
|
|
660
|
-
# :content_only - apply visualization only to text content, not
|
|
661
|
-
# to structural indentation whitespace.
|
|
662
|
-
def character_visualization
|
|
663
|
-
val = @resolver.resolve(:character_visualization)
|
|
664
|
-
# Coerce symbol booleans that may arrive via ENV (env_schema uses :symbol type
|
|
665
|
-
# so "true"/"false" env strings become :true/:false symbols)
|
|
666
|
-
case val
|
|
667
|
-
when true, :true then true # rubocop:disable Lint/BooleanSymbol
|
|
668
|
-
when false, :false then false # rubocop:disable Lint/BooleanSymbol
|
|
669
|
-
else val # true/false from programmatic, or :content_only
|
|
670
|
-
end
|
|
671
|
-
end
|
|
672
|
-
|
|
673
|
-
def character_visualization=(value)
|
|
674
|
-
self.class.validate_config_value!(:character_visualization, value)
|
|
675
|
-
@resolver.set_programmatic(:character_visualization, value)
|
|
676
|
-
end
|
|
677
|
-
|
|
678
|
-
def algorithm
|
|
679
|
-
@resolver.resolve(:algorithm)
|
|
680
|
-
end
|
|
681
|
-
|
|
682
|
-
def algorithm=(value)
|
|
683
|
-
self.class.validate_config_value!(:algorithm, value)
|
|
684
|
-
@resolver.set_programmatic(:algorithm, value)
|
|
685
|
-
end
|
|
686
|
-
|
|
687
|
-
# XML parser backend (:sax or :dom, default :sax)
|
|
688
|
-
def parser
|
|
689
|
-
@resolver.resolve(:parser)
|
|
690
|
-
end
|
|
691
|
-
|
|
692
|
-
def parser=(value)
|
|
693
|
-
self.class.validate_config_value!(:parser, value)
|
|
694
|
-
@resolver.set_programmatic(:parser, value)
|
|
695
|
-
end
|
|
696
|
-
|
|
697
|
-
# Theme name (:light, :dark, :retro, :claude)
|
|
698
|
-
def theme
|
|
699
|
-
@resolver.resolve(:theme)
|
|
700
|
-
end
|
|
701
|
-
|
|
702
|
-
def theme=(value)
|
|
703
|
-
self.class.validate_config_value!(:theme, value)
|
|
704
|
-
@resolver.set_programmatic(:theme, value)
|
|
705
|
-
end
|
|
706
|
-
|
|
707
|
-
# Theme inheritance (custom theme with base + overrides)
|
|
708
|
-
def theme_inheritance
|
|
709
|
-
@resolver.resolve(:theme_inheritance)
|
|
710
|
-
end
|
|
711
|
-
|
|
712
|
-
def theme_inheritance=(value)
|
|
713
|
-
@resolver.set_programmatic(:theme_inheritance, value)
|
|
714
|
-
end
|
|
715
|
-
|
|
716
|
-
# Full custom theme hash
|
|
717
|
-
def custom_theme
|
|
718
|
-
@resolver.resolve(:custom_theme)
|
|
719
|
-
end
|
|
720
|
-
|
|
721
|
-
def custom_theme=(value)
|
|
722
|
-
@resolver.set_programmatic(:custom_theme, value)
|
|
723
|
-
end
|
|
724
|
-
|
|
725
|
-
# File size limit in bytes (default 5MB)
|
|
726
|
-
def max_file_size
|
|
727
|
-
@resolver.resolve(:max_file_size)
|
|
728
|
-
end
|
|
729
|
-
|
|
730
|
-
def max_file_size=(value)
|
|
731
|
-
@resolver.set_programmatic(:max_file_size, value)
|
|
732
|
-
end
|
|
733
|
-
|
|
734
|
-
# Maximum node count in tree (default 10,000)
|
|
735
|
-
def max_node_count
|
|
736
|
-
@resolver.resolve(:max_node_count)
|
|
737
|
-
end
|
|
738
|
-
|
|
739
|
-
def max_node_count=(value)
|
|
740
|
-
@resolver.set_programmatic(:max_node_count, value)
|
|
741
|
-
end
|
|
742
|
-
|
|
743
|
-
# Maximum diff output lines (default 10,000)
|
|
744
|
-
def max_diff_lines
|
|
745
|
-
@resolver.resolve(:max_diff_lines)
|
|
746
|
-
end
|
|
747
|
-
|
|
748
|
-
def max_diff_lines=(value)
|
|
749
|
-
@resolver.set_programmatic(:max_diff_lines, value)
|
|
750
|
-
end
|
|
337
|
+
# --- Attribute declarations --------------------------------------
|
|
338
|
+
|
|
339
|
+
config_key :mode, type: :symbol,
|
|
340
|
+
enum: %i[by_line by_object pretty_diff],
|
|
341
|
+
default: :by_line
|
|
342
|
+
config_key :use_color, type: :boolean,
|
|
343
|
+
default: -> { ColorDetector.supports_color? }
|
|
344
|
+
config_key :context_lines, type: :integer, default: 3
|
|
345
|
+
config_key :grouping_lines, type: :integer, default: 10
|
|
346
|
+
config_key :show_diffs, type: :symbol,
|
|
347
|
+
enum: %i[all normative informative],
|
|
348
|
+
default: :all
|
|
349
|
+
config_key :verbose_diff, type: :boolean, default: false
|
|
350
|
+
config_key :algorithm, type: :symbol, enum: %i[dom semantic],
|
|
351
|
+
default: :dom
|
|
352
|
+
config_key :parser, type: :symbol, enum: %i[sax dom], default: :sax
|
|
353
|
+
|
|
354
|
+
config_key :show_raw_inputs, type: :boolean, default: false
|
|
355
|
+
config_key :show_raw_expected, type: :boolean, default: false
|
|
356
|
+
config_key :show_raw_received, type: :boolean, default: false
|
|
357
|
+
config_key :show_preprocessed_inputs, type: :boolean, default: false
|
|
358
|
+
config_key :show_preprocessed_expected, type: :boolean, default: false
|
|
359
|
+
config_key :show_preprocessed_received, type: :boolean, default: false
|
|
360
|
+
config_key :show_prettyprint_inputs, type: :boolean, default: false
|
|
361
|
+
config_key :show_prettyprint_expected, type: :boolean, default: false
|
|
362
|
+
config_key :show_prettyprint_received, type: :boolean, default: false
|
|
363
|
+
config_key :show_line_numbered_inputs, type: :boolean, default: false
|
|
364
|
+
|
|
365
|
+
config_key :display_format, type: :symbol, enum: %i[raw canonical],
|
|
366
|
+
default: :raw
|
|
367
|
+
config_key :display_preprocessing, type: :symbol,
|
|
368
|
+
enum: %i[none pretty_print
|
|
369
|
+
normalize_pretty_print c14n],
|
|
370
|
+
default: :none
|
|
371
|
+
|
|
372
|
+
config_key :preserve_whitespace_elements,
|
|
373
|
+
type: :string_array,
|
|
374
|
+
default: [],
|
|
375
|
+
coerce: ->(v) { Array(v).map(&:to_s) },
|
|
376
|
+
getter_coerce: ->(v) { v || [] }
|
|
377
|
+
config_key :collapse_whitespace_elements,
|
|
378
|
+
type: :string_array,
|
|
379
|
+
default: [],
|
|
380
|
+
coerce: ->(v) { Array(v).map(&:to_s) },
|
|
381
|
+
getter_coerce: ->(v) { v || [] }
|
|
382
|
+
config_key :strip_whitespace_elements,
|
|
383
|
+
type: :string_array,
|
|
384
|
+
default: [],
|
|
385
|
+
coerce: ->(v) { Array(v).map(&:to_s) },
|
|
386
|
+
getter_coerce: ->(v) { v || [] }
|
|
387
|
+
|
|
388
|
+
config_key :pretty_printed_expected, type: :boolean, default: false
|
|
389
|
+
config_key :pretty_printed_received, type: :boolean, default: false
|
|
390
|
+
config_key :pretty_printer_sort_attributes, type: :boolean,
|
|
391
|
+
default: false
|
|
392
|
+
config_key :compact_semantic_report, type: :boolean, default: false
|
|
393
|
+
config_key :expand_difference, type: :boolean, default: false
|
|
394
|
+
|
|
395
|
+
# Accepts +true+, +false+, or +:content_only+. ENV-supplied
|
|
396
|
+
# +"true"/"false"+ strings arrive as +:true/:false+ (TypeConverter
|
|
397
|
+
# uses the +:symbol+ type) so the getter coerces them back to
|
|
398
|
+
# booleans.
|
|
399
|
+
config_key :character_visualization,
|
|
400
|
+
type: :symbol,
|
|
401
|
+
enum: [true, false, :content_only],
|
|
402
|
+
default: true,
|
|
403
|
+
getter_coerce: lambda { |val|
|
|
404
|
+
case val
|
|
405
|
+
when true, :true then true # rubocop:disable Lint/BooleanSymbol
|
|
406
|
+
when false, :false then false # rubocop:disable Lint/BooleanSymbol
|
|
407
|
+
else val
|
|
408
|
+
end
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
config_key :theme, type: :symbol,
|
|
412
|
+
enum: %i[light dark retro claude cyberpunk],
|
|
413
|
+
default: :dark
|
|
414
|
+
config_key :theme_inheritance, type: :pass_through, default: nil
|
|
415
|
+
config_key :custom_theme, type: :pass_through, default: nil
|
|
416
|
+
|
|
417
|
+
config_key :max_file_size, type: :integer, default: 5_242_880
|
|
418
|
+
config_key :max_node_count, type: :integer, default: 10_000
|
|
419
|
+
config_key :max_diff_lines, type: :integer, default: 10_000
|
|
420
|
+
|
|
421
|
+
# Pretty-printer keys are declared here so they participate in
|
|
422
|
+
# +config_keys+ (for EnvSchema discovery and validation) even
|
|
423
|
+
# though user code reaches them via the +PrettyPrinterConfig+
|
|
424
|
+
# facade through +DiffConfig#pretty_printer+.
|
|
425
|
+
config_key :pretty_printer_indent, type: :integer, default: 2
|
|
426
|
+
config_key :pretty_printer_indent_type, type: :symbol,
|
|
427
|
+
enum: %i[space tab],
|
|
428
|
+
default: :space
|
|
429
|
+
|
|
430
|
+
# Enum constraint map derived from declared config keys. Kept as a
|
|
431
|
+
# constant for backward compatibility with code that referenced
|
|
432
|
+
# +DiffConfig::VALID_ENUM_VALUES+ directly. Must be assigned AFTER
|
|
433
|
+
# all +config_key+ declarations above so the registry is populated.
|
|
434
|
+
VALID_ENUM_VALUES = enum_values.freeze
|
|
751
435
|
|
|
752
436
|
# Build diff options
|
|
753
437
|
def to_h
|
|
@@ -792,45 +476,9 @@ module Canon
|
|
|
792
476
|
private
|
|
793
477
|
|
|
794
478
|
def build_resolver(format)
|
|
795
|
-
defaults = {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
context_lines: 3,
|
|
799
|
-
grouping_lines: 10,
|
|
800
|
-
show_diffs: :all,
|
|
801
|
-
verbose_diff: false,
|
|
802
|
-
algorithm: :dom,
|
|
803
|
-
parser: :sax,
|
|
804
|
-
show_raw_inputs: false,
|
|
805
|
-
show_raw_expected: false,
|
|
806
|
-
show_raw_received: false,
|
|
807
|
-
show_preprocessed_inputs: false,
|
|
808
|
-
show_preprocessed_expected: false,
|
|
809
|
-
show_preprocessed_received: false,
|
|
810
|
-
show_prettyprint_inputs: false,
|
|
811
|
-
show_prettyprint_expected: false,
|
|
812
|
-
show_prettyprint_received: false,
|
|
813
|
-
show_line_numbered_inputs: false,
|
|
814
|
-
character_visualization: true, # true, false, :content_only
|
|
815
|
-
display_format: :raw, # :raw = no formatting, :canonical = HTML-aware formatting
|
|
816
|
-
display_preprocessing: :none, # :none, :pretty_print, :c14n
|
|
817
|
-
pretty_printer_indent: 2,
|
|
818
|
-
pretty_printer_indent_type: :space, # :space or :tab
|
|
819
|
-
preserve_whitespace_elements: [],
|
|
820
|
-
collapse_whitespace_elements: [],
|
|
821
|
-
strip_whitespace_elements: [],
|
|
822
|
-
pretty_printed_expected: false,
|
|
823
|
-
pretty_printed_received: false,
|
|
824
|
-
pretty_printer_sort_attributes: false,
|
|
825
|
-
compact_semantic_report: false,
|
|
826
|
-
expand_difference: false,
|
|
827
|
-
max_file_size: 5_242_880, # 5MB in bytes
|
|
828
|
-
max_node_count: 10_000, # Maximum nodes in tree
|
|
829
|
-
max_diff_lines: 10_000, # Maximum diff output lines
|
|
830
|
-
theme: :dark, # Default theme
|
|
831
|
-
theme_inheritance: nil, # Custom theme with base + overrides
|
|
832
|
-
custom_theme: nil, # Full custom theme hash
|
|
833
|
-
}
|
|
479
|
+
defaults = self.class.config_keys.each_with_object({}) do |(k, _m), h|
|
|
480
|
+
h[k] = self.class.resolve_default(k)
|
|
481
|
+
end
|
|
834
482
|
|
|
835
483
|
env = format ? EnvProvider.load_diff_for_format(format) : {}
|
|
836
484
|
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "formatting_detector"
|
|
4
|
-
require_relative "xml_serialization_formatter"
|
|
5
|
-
require_relative "../comparison/compare_profile"
|
|
6
|
-
require_relative "../comparison/whitespace_sensitivity"
|
|
7
|
-
|
|
8
3
|
module Canon
|
|
9
4
|
module Diff
|
|
10
5
|
# Classifies DiffNodes as normative (affects equivalence) or informative (doesn't affect equivalence)
|