coradoc 1.1.8 → 2.0.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/.rspec +1 -1
- data/Rakefile +3 -12
- data/exe/coradoc +21 -2
- data/lib/coradoc/cli.rb +185 -91
- data/lib/coradoc/configurable.rb +527 -0
- data/lib/coradoc/coradoc.rb +463 -0
- data/lib/coradoc/core_model/annotation_block.rb +57 -0
- data/lib/coradoc/core_model/base.rb +172 -0
- data/lib/coradoc/core_model/bibliography.rb +41 -0
- data/lib/coradoc/core_model/bibliography_entry.rb +48 -0
- data/lib/coradoc/core_model/block.rb +63 -0
- data/lib/coradoc/core_model/children_content.rb +53 -0
- data/lib/coradoc/core_model/comment_block.rb +10 -0
- data/lib/coradoc/core_model/definition_item.rb +46 -0
- data/lib/coradoc/core_model/definition_list.rb +28 -0
- data/lib/coradoc/core_model/element_attribute.rb +26 -0
- data/lib/coradoc/core_model/example_block.rb +10 -0
- data/lib/coradoc/core_model/footnote.rb +92 -0
- data/lib/coradoc/core_model/horizontal_rule_block.rb +10 -0
- data/lib/coradoc/core_model/id_generator.rb +16 -0
- data/lib/coradoc/core_model/image.rb +66 -0
- data/lib/coradoc/core_model/inline_element.rb +140 -0
- data/lib/coradoc/core_model/list_block.rb +135 -0
- data/lib/coradoc/core_model/list_item.rb +142 -0
- data/lib/coradoc/core_model/listing_block.rb +13 -0
- data/lib/coradoc/core_model/literal_block.rb +10 -0
- data/lib/coradoc/core_model/metadata.rb +79 -0
- data/lib/coradoc/core_model/open_block.rb +10 -0
- data/lib/coradoc/core_model/paragraph_block.rb +10 -0
- data/lib/coradoc/core_model/pass_block.rb +10 -0
- data/lib/coradoc/core_model/quote_block.rb +12 -0
- data/lib/coradoc/core_model/reviewer_block.rb +10 -0
- data/lib/coradoc/core_model/sidebar_block.rb +10 -0
- data/lib/coradoc/core_model/source_block.rb +10 -0
- data/lib/coradoc/core_model/structural_element.rb +94 -0
- data/lib/coradoc/core_model/table.rb +148 -0
- data/lib/coradoc/core_model/term.rb +53 -0
- data/lib/coradoc/core_model/text_content.rb +22 -0
- data/lib/coradoc/core_model/toc.rb +105 -0
- data/lib/coradoc/core_model/toc_generator.rb +151 -0
- data/lib/coradoc/core_model/verse_block.rb +12 -0
- data/lib/coradoc/core_model.rb +77 -0
- data/lib/coradoc/document_builder.rb +184 -0
- data/lib/coradoc/document_manipulator.rb +203 -0
- data/lib/coradoc/errors.rb +312 -0
- data/lib/coradoc/format_module.rb +49 -0
- data/lib/coradoc/hooks.rb +176 -0
- data/lib/coradoc/input.rb +17 -7
- data/lib/coradoc/logger.rb +54 -0
- data/lib/coradoc/output.rb +17 -6
- data/lib/coradoc/performance_regression.rb +109 -0
- data/lib/coradoc/processor_registry.rb +50 -0
- data/lib/coradoc/query.rb +455 -0
- data/lib/coradoc/registry.rb +156 -0
- data/lib/coradoc/serializer/registry.rb +150 -0
- data/lib/coradoc/transform.rb +11 -0
- data/lib/coradoc/validation.rb +646 -0
- data/lib/coradoc/version.rb +1 -1
- data/lib/coradoc/visitor.rb +283 -0
- data/lib/coradoc.rb +40 -19
- metadata +67 -277
- data/.editorconfig +0 -15
- data/.envrc +0 -1
- data/.irbrc +0 -1
- data/.pryrc.sample +0 -1
- data/.rubocop.yml +0 -14
- data/.rubocop_todo.yml +0 -179
- data/CHANGELOG.md +0 -9
- data/CODE_OF_CONDUCT.md +0 -84
- data/Dockerfile +0 -19
- data/Gemfile +0 -16
- data/LICENSE.txt +0 -21
- data/Makefile +0 -35
- data/README.Docker.adoc +0 -57
- data/README.adoc +0 -119
- data/coradoc.gemspec +0 -40
- data/docker-compose.yml +0 -14
- data/exe/reverse_adoc +0 -81
- data/exe/w2a +0 -60
- data/flake.lock +0 -114
- data/flake.nix +0 -135
- data/lib/coradoc/converter.rb +0 -144
- data/lib/coradoc/document.rb +0 -77
- data/lib/coradoc/element/admonition.rb +0 -18
- data/lib/coradoc/element/attribute.rb +0 -36
- data/lib/coradoc/element/attribute_list.rb +0 -138
- data/lib/coradoc/element/audio.rb +0 -33
- data/lib/coradoc/element/author.rb +0 -24
- data/lib/coradoc/element/base.rb +0 -92
- data/lib/coradoc/element/bibliography.rb +0 -24
- data/lib/coradoc/element/bibliography_entry.rb +0 -24
- data/lib/coradoc/element/block/core.rb +0 -76
- data/lib/coradoc/element/block/example.rb +0 -23
- data/lib/coradoc/element/block/listing.rb +0 -21
- data/lib/coradoc/element/block/literal.rb +0 -21
- data/lib/coradoc/element/block/open.rb +0 -22
- data/lib/coradoc/element/block/pass.rb +0 -21
- data/lib/coradoc/element/block/quote.rb +0 -19
- data/lib/coradoc/element/block/reviewer_comment.rb +0 -19
- data/lib/coradoc/element/block/side.rb +0 -19
- data/lib/coradoc/element/block/sourcecode.rb +0 -21
- data/lib/coradoc/element/block.rb +0 -17
- data/lib/coradoc/element/break.rb +0 -11
- data/lib/coradoc/element/comment_block.rb +0 -22
- data/lib/coradoc/element/comment_line.rb +0 -18
- data/lib/coradoc/element/document_attributes.rb +0 -33
- data/lib/coradoc/element/header.rb +0 -22
- data/lib/coradoc/element/image/block_image.rb +0 -32
- data/lib/coradoc/element/image/core.rb +0 -58
- data/lib/coradoc/element/image/inline_image.rb +0 -12
- data/lib/coradoc/element/image.rb +0 -10
- data/lib/coradoc/element/include.rb +0 -18
- data/lib/coradoc/element/inline/anchor.rb +0 -19
- data/lib/coradoc/element/inline/attribute_reference.rb +0 -19
- data/lib/coradoc/element/inline/bold.rb +0 -25
- data/lib/coradoc/element/inline/cross_reference.rb +0 -46
- data/lib/coradoc/element/inline/footnote.rb +0 -24
- data/lib/coradoc/element/inline/hard_line_break.rb +0 -11
- data/lib/coradoc/element/inline/highlight.rb +0 -25
- data/lib/coradoc/element/inline/italic.rb +0 -25
- data/lib/coradoc/element/inline/link.rb +0 -42
- data/lib/coradoc/element/inline/monospace.rb +0 -25
- data/lib/coradoc/element/inline/quotation.rb +0 -20
- data/lib/coradoc/element/inline/small.rb +0 -19
- data/lib/coradoc/element/inline/span.rb +0 -37
- data/lib/coradoc/element/inline/subscript.rb +0 -20
- data/lib/coradoc/element/inline/superscript.rb +0 -20
- data/lib/coradoc/element/inline/underline.rb +0 -19
- data/lib/coradoc/element/inline.rb +0 -23
- data/lib/coradoc/element/list/core.rb +0 -51
- data/lib/coradoc/element/list/definition.rb +0 -29
- data/lib/coradoc/element/list/ordered.rb +0 -17
- data/lib/coradoc/element/list/unordered.rb +0 -17
- data/lib/coradoc/element/list.rb +0 -13
- data/lib/coradoc/element/list_item.rb +0 -98
- data/lib/coradoc/element/list_item_definition.rb +0 -32
- data/lib/coradoc/element/paragraph.rb +0 -37
- data/lib/coradoc/element/revision.rb +0 -27
- data/lib/coradoc/element/section.rb +0 -62
- data/lib/coradoc/element/table.rb +0 -91
- data/lib/coradoc/element/tag.rb +0 -19
- data/lib/coradoc/element/term.rb +0 -22
- data/lib/coradoc/element/text_element.rb +0 -92
- data/lib/coradoc/element/title.rb +0 -62
- data/lib/coradoc/element/video.rb +0 -50
- data/lib/coradoc/generator.rb +0 -19
- data/lib/coradoc/input/adoc.rb +0 -30
- data/lib/coradoc/input/docx.rb +0 -64
- data/lib/coradoc/input/html/LICENSE.txt +0 -25
- data/lib/coradoc/input/html/README.adoc +0 -308
- data/lib/coradoc/input/html/cleaner.rb +0 -142
- data/lib/coradoc/input/html/config.rb +0 -77
- data/lib/coradoc/input/html/converters/a.rb +0 -52
- data/lib/coradoc/input/html/converters/aside.rb +0 -16
- data/lib/coradoc/input/html/converters/audio.rb +0 -29
- data/lib/coradoc/input/html/converters/base.rb +0 -108
- data/lib/coradoc/input/html/converters/blockquote.rb +0 -22
- data/lib/coradoc/input/html/converters/br.rb +0 -15
- data/lib/coradoc/input/html/converters/bypass.rb +0 -81
- data/lib/coradoc/input/html/converters/code.rb +0 -23
- data/lib/coradoc/input/html/converters/div.rb +0 -19
- data/lib/coradoc/input/html/converters/dl.rb +0 -62
- data/lib/coradoc/input/html/converters/drop.rb +0 -26
- data/lib/coradoc/input/html/converters/em.rb +0 -21
- data/lib/coradoc/input/html/converters/figure.rb +0 -25
- data/lib/coradoc/input/html/converters/h.rb +0 -42
- data/lib/coradoc/input/html/converters/head.rb +0 -23
- data/lib/coradoc/input/html/converters/hr.rb +0 -15
- data/lib/coradoc/input/html/converters/ignore.rb +0 -20
- data/lib/coradoc/input/html/converters/img.rb +0 -110
- data/lib/coradoc/input/html/converters/li.rb +0 -17
- data/lib/coradoc/input/html/converters/mark.rb +0 -19
- data/lib/coradoc/input/html/converters/markup.rb +0 -31
- data/lib/coradoc/input/html/converters/math.rb +0 -38
- data/lib/coradoc/input/html/converters/ol.rb +0 -65
- data/lib/coradoc/input/html/converters/p.rb +0 -23
- data/lib/coradoc/input/html/converters/pass_through.rb +0 -17
- data/lib/coradoc/input/html/converters/pre.rb +0 -55
- data/lib/coradoc/input/html/converters/q.rb +0 -16
- data/lib/coradoc/input/html/converters/strong.rb +0 -20
- data/lib/coradoc/input/html/converters/sub.rb +0 -22
- data/lib/coradoc/input/html/converters/sup.rb +0 -22
- data/lib/coradoc/input/html/converters/table.rb +0 -319
- data/lib/coradoc/input/html/converters/td.rb +0 -81
- data/lib/coradoc/input/html/converters/text.rb +0 -32
- data/lib/coradoc/input/html/converters/th.rb +0 -18
- data/lib/coradoc/input/html/converters/tr.rb +0 -22
- data/lib/coradoc/input/html/converters/video.rb +0 -29
- data/lib/coradoc/input/html/converters.rb +0 -59
- data/lib/coradoc/input/html/errors.rb +0 -14
- data/lib/coradoc/input/html/html_converter.rb +0 -168
- data/lib/coradoc/input/html/plugin.rb +0 -131
- data/lib/coradoc/input/html/plugins/plateau.rb +0 -213
- data/lib/coradoc/input/html/postprocessor.rb +0 -220
- data/lib/coradoc/input/html.rb +0 -61
- data/lib/coradoc/legacy_parser.rb +0 -200
- data/lib/coradoc/oscal.rb +0 -99
- data/lib/coradoc/output/adoc.rb +0 -19
- data/lib/coradoc/output/coradoc_tree_debug.rb +0 -21
- data/lib/coradoc/parser/asciidoc/admonition.rb +0 -24
- data/lib/coradoc/parser/asciidoc/attribute_list.rb +0 -89
- data/lib/coradoc/parser/asciidoc/base.rb +0 -87
- data/lib/coradoc/parser/asciidoc/bibliography.rb +0 -29
- data/lib/coradoc/parser/asciidoc/block.rb +0 -94
- data/lib/coradoc/parser/asciidoc/citation.rb +0 -30
- data/lib/coradoc/parser/asciidoc/content.rb +0 -64
- data/lib/coradoc/parser/asciidoc/document_attributes.rb +0 -25
- data/lib/coradoc/parser/asciidoc/header.rb +0 -29
- data/lib/coradoc/parser/asciidoc/inline.rb +0 -195
- data/lib/coradoc/parser/asciidoc/list.rb +0 -115
- data/lib/coradoc/parser/asciidoc/paragraph.rb +0 -54
- data/lib/coradoc/parser/asciidoc/section.rb +0 -61
- data/lib/coradoc/parser/asciidoc/table.rb +0 -32
- data/lib/coradoc/parser/asciidoc/term.rb +0 -41
- data/lib/coradoc/parser/asciidoc/text.rb +0 -158
- data/lib/coradoc/parser/base.rb +0 -40
- data/lib/coradoc/parser.rb +0 -11
- data/lib/coradoc/reverse_adoc.rb +0 -18
- data/lib/coradoc/transformer.rb +0 -476
- data/lib/coradoc/util.rb +0 -12
- data/lib/reverse_adoc.rb +0 -20
- data/utils/inspect_asciidoc.rb +0 -29
- data/utils/parser_analyzer.rb +0 -66
- data/utils/round_trip.rb +0 -53
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
# Declared interface contract for format modules.
|
|
5
|
+
#
|
|
6
|
+
# Format modules registered via Coradoc.register_format must implement:
|
|
7
|
+
#
|
|
8
|
+
# Required:
|
|
9
|
+
# - parse_to_core(input, options={}) → CoreModel::Base
|
|
10
|
+
# - serialize(model, **options) → String
|
|
11
|
+
#
|
|
12
|
+
# Optional:
|
|
13
|
+
# - parse(input, options={}) → format-specific model
|
|
14
|
+
# - handles_model?(model) → Boolean
|
|
15
|
+
# - to_core(model) → CoreModel::Base
|
|
16
|
+
# - serialize? → Boolean
|
|
17
|
+
#
|
|
18
|
+
module FormatModule
|
|
19
|
+
MINIMUM_PARSE_METHODS = %i[parse_to_core parse].freeze
|
|
20
|
+
REQUIRED_METHODS = %i[serialize].freeze
|
|
21
|
+
|
|
22
|
+
# Default implementations for optional format module methods.
|
|
23
|
+
# Format modules are auto-extended with this during registration.
|
|
24
|
+
module Interface
|
|
25
|
+
def handles_model?(_model)
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def serialize?
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Validate that a format module implements the minimum interface.
|
|
35
|
+
# Warns to $stderr if methods are missing. Returns true if valid.
|
|
36
|
+
def self.validate!(format_module, format_name)
|
|
37
|
+
has_parse = MINIMUM_PARSE_METHODS.any? { |m| format_module.public_methods.include?(m) }
|
|
38
|
+
has_serialize = REQUIRED_METHODS.all? { |m| format_module.public_methods.include?(m) }
|
|
39
|
+
|
|
40
|
+
return true if has_parse && has_serialize
|
|
41
|
+
|
|
42
|
+
missing = []
|
|
43
|
+
missing << 'parse_to_core or parse' unless has_parse
|
|
44
|
+
missing << 'serialize' unless has_serialize
|
|
45
|
+
warn "Coradoc: format :#{format_name} (#{format_module}) missing: #{missing.join(', ')}"
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Coradoc
|
|
6
|
+
module Hooks
|
|
7
|
+
HOOK_POINTS = {
|
|
8
|
+
before_parse: 'Called before parsing text content. Receives (content, format:, **options). Should return modified content.',
|
|
9
|
+
after_parse: 'Called after parsing. Receives (model, format:, **options). Should return modified model.',
|
|
10
|
+
before_transform: 'Called before transforming model. Receives (model, direction:, **options). Should return modified model.',
|
|
11
|
+
after_transform: 'Called after transforming model. Receives (model, direction:, **options). Should return modified model.',
|
|
12
|
+
before_serialize: 'Called before serializing model. Receives (model, format:, **options). Should return modified model.',
|
|
13
|
+
after_serialize: 'Called after serializing. Receives (output, format:, **options). Should return modified output.',
|
|
14
|
+
on_error: 'Called when an error occurs. Receives (error, context). Can re-raise or return fallback value.'
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
attr_accessor :strict_mode
|
|
19
|
+
|
|
20
|
+
def register(hook_point, priority: 100, name: nil, &block)
|
|
21
|
+
validate_hook_point!(hook_point)
|
|
22
|
+
validate_block!(block, hook_point)
|
|
23
|
+
|
|
24
|
+
hook_id = name || generate_hook_id(hook_point)
|
|
25
|
+
registry[hook_point] ||= []
|
|
26
|
+
registry[hook_point] << {
|
|
27
|
+
id: hook_id,
|
|
28
|
+
priority: priority,
|
|
29
|
+
sequence: next_sequence,
|
|
30
|
+
callback: block
|
|
31
|
+
}
|
|
32
|
+
registry[hook_point].sort_by! { |h| [h[:priority], h[:sequence]] }
|
|
33
|
+
hook_id
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def remove(hook_point, hook_id)
|
|
37
|
+
validate_hook_point!(hook_point)
|
|
38
|
+
return false unless registry[hook_point]
|
|
39
|
+
|
|
40
|
+
original_size = registry[hook_point].size
|
|
41
|
+
registry[hook_point].reject! { |h| h[:id] == hook_id }
|
|
42
|
+
registry[hook_point].size < original_size
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def clear(hook_point)
|
|
46
|
+
validate_hook_point!(hook_point)
|
|
47
|
+
removed = registry[hook_point]&.size || 0
|
|
48
|
+
registry.delete(hook_point)
|
|
49
|
+
removed
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def clear_all
|
|
53
|
+
total = registry.values.sum(&:size)
|
|
54
|
+
@registry = {}
|
|
55
|
+
@sequence_counter = nil
|
|
56
|
+
total
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def registered?(hook_point)
|
|
60
|
+
validate_hook_point!(hook_point)
|
|
61
|
+
registry[hook_point]&.any? || false
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def list(hook_point = nil)
|
|
65
|
+
if hook_point
|
|
66
|
+
validate_hook_point!(hook_point)
|
|
67
|
+
registry[hook_point]&.map { |h| h.merge(point: hook_point) } || []
|
|
68
|
+
else
|
|
69
|
+
registry.flat_map do |point, hooks|
|
|
70
|
+
hooks.map { |h| h.merge(point: point) }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def invoke(hook_point, *args, **kwargs)
|
|
76
|
+
validate_hook_point!(hook_point)
|
|
77
|
+
return args.first if args.one? && !registry[hook_point]&.any?
|
|
78
|
+
|
|
79
|
+
result = args.first
|
|
80
|
+
registry[hook_point].each do |hook|
|
|
81
|
+
result = invoke_hook(hook[:callback], result, args, kwargs)
|
|
82
|
+
end
|
|
83
|
+
result
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def with_hooks(hook_point, *args, **kwargs)
|
|
87
|
+
validate_hook_point!(hook_point)
|
|
88
|
+
|
|
89
|
+
modified_args = invoke(hook_point, *args, **kwargs)
|
|
90
|
+
result = yield(*modified_args)
|
|
91
|
+
|
|
92
|
+
after_point = "after_#{hook_point.to_s.sub('before_', '')}".to_sym
|
|
93
|
+
result = invoke(after_point, result, **kwargs) if HOOK_POINTS.key?(after_point)
|
|
94
|
+
|
|
95
|
+
result
|
|
96
|
+
rescue StandardError => e
|
|
97
|
+
invoke_error_hooks(e, hook_point, args, kwargs)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def documentation(hook_point = nil)
|
|
101
|
+
if hook_point
|
|
102
|
+
validate_hook_point!(hook_point)
|
|
103
|
+
HOOK_POINTS[hook_point]
|
|
104
|
+
else
|
|
105
|
+
HOOK_POINTS.dup
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def registry
|
|
112
|
+
@registry ||= {}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def next_sequence
|
|
116
|
+
@sequence_counter = (@sequence_counter || 0) + 1
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def validate_hook_point!(hook_point)
|
|
120
|
+
return if HOOK_POINTS.key?(hook_point)
|
|
121
|
+
|
|
122
|
+
valid_points = HOOK_POINTS.keys.join(', ')
|
|
123
|
+
raise ArgumentError,
|
|
124
|
+
"Unknown hook point: #{hook_point}. Valid points: #{valid_points}"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def validate_block!(block, hook_point)
|
|
128
|
+
return if block
|
|
129
|
+
|
|
130
|
+
raise ArgumentError,
|
|
131
|
+
"Block required for hook registration: #{hook_point}"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def generate_hook_id(hook_point)
|
|
135
|
+
"#{hook_point}_#{SecureRandom.hex(8)}"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def invoke_hook(callback, result, _args, kwargs)
|
|
139
|
+
arity = callback.arity
|
|
140
|
+
|
|
141
|
+
if kwargs.empty?
|
|
142
|
+
case arity
|
|
143
|
+
when 0
|
|
144
|
+
callback.call
|
|
145
|
+
else
|
|
146
|
+
callback.call(result)
|
|
147
|
+
end
|
|
148
|
+
else
|
|
149
|
+
callback.call(result, **kwargs)
|
|
150
|
+
end
|
|
151
|
+
rescue StandardError => e
|
|
152
|
+
raise if @strict_mode
|
|
153
|
+
|
|
154
|
+
Coradoc::Logger.warn("Hook failed: #{e.message}")
|
|
155
|
+
result
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def invoke_error_hooks(error, hook_point, args, kwargs)
|
|
159
|
+
context = {
|
|
160
|
+
hook_point: hook_point,
|
|
161
|
+
args: args,
|
|
162
|
+
kwargs: kwargs
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if registry[:on_error]&.any?
|
|
166
|
+
registry[:on_error].each do |hook|
|
|
167
|
+
result = hook[:callback].call(error, context)
|
|
168
|
+
return result if result
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
raise error
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
data/lib/coradoc/input.rb
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'processor_registry'
|
|
2
4
|
|
|
3
5
|
module Coradoc
|
|
6
|
+
# Input module for document ingestion
|
|
7
|
+
#
|
|
8
|
+
# Provides a unified interface for document input processing.
|
|
9
|
+
# Format-specific input processors register themselves with this module.
|
|
10
|
+
#
|
|
11
|
+
# @example Registering an input processor
|
|
12
|
+
# Coradoc::Input.define(MyHtmlProcessor)
|
|
13
|
+
#
|
|
14
|
+
# @example Using a registered processor
|
|
15
|
+
# processor = Coradoc::Input.for(:html)
|
|
16
|
+
# document = processor.convert(html_content)
|
|
17
|
+
#
|
|
4
18
|
module Input
|
|
5
|
-
|
|
6
|
-
|
|
19
|
+
extend ProcessorRegistry
|
|
20
|
+
self.error_label = 'input processor'
|
|
7
21
|
end
|
|
8
22
|
end
|
|
9
|
-
|
|
10
|
-
require "coradoc/input/adoc"
|
|
11
|
-
require "coradoc/input/docx"
|
|
12
|
-
require "coradoc/input/html"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
class Logger
|
|
5
|
+
BADGE = 'Coradoc'
|
|
6
|
+
|
|
7
|
+
COLORS = {
|
|
8
|
+
error: "\e[31m", # Red
|
|
9
|
+
info: "\e[34m", # Blue
|
|
10
|
+
reset: "\e[m", # Reset
|
|
11
|
+
success: "\e[32m", # Green
|
|
12
|
+
warn: "\e[33m", # Yellow
|
|
13
|
+
bold: "\e[1m",
|
|
14
|
+
unbold: "\e[22m"
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def self.error(message)
|
|
18
|
+
log(message, :error)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.info(message)
|
|
22
|
+
log(message, :info)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.success(message)
|
|
26
|
+
log(message, :success)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.warn(message)
|
|
30
|
+
log(message, :warn)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.log(message, type)
|
|
34
|
+
Warning.warn format_message(message, type)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.format_message(message, type)
|
|
38
|
+
colorize(
|
|
39
|
+
"\n[#{BADGE}] #{COLORS[:bold]}#{type.upcase}#{COLORS[:unbold]}" \
|
|
40
|
+
": #{message}\n",
|
|
41
|
+
type
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.colorize(message, type)
|
|
46
|
+
io = type == :warn ? $stderr : $stdout
|
|
47
|
+
return message unless io.tty?
|
|
48
|
+
|
|
49
|
+
"#{COLORS[type]}#{message}#{COLORS[:reset]}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private_class_method :log, :format_message, :colorize
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/coradoc/output.rb
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'processor_registry'
|
|
2
4
|
|
|
3
5
|
module Coradoc
|
|
6
|
+
# Output module for document serialization
|
|
7
|
+
#
|
|
8
|
+
# Provides a unified interface for document output processing.
|
|
9
|
+
# Format-specific output processors register themselves with this module.
|
|
10
|
+
#
|
|
11
|
+
# @example Registering an output processor
|
|
12
|
+
# Coradoc::Output.define(MyHtmlProcessor)
|
|
13
|
+
#
|
|
14
|
+
# @example Using a registered processor
|
|
15
|
+
# processor = Coradoc::Output.get(:html_static)
|
|
16
|
+
# html = processor.processor_execute(document, {})
|
|
17
|
+
#
|
|
4
18
|
module Output
|
|
5
|
-
|
|
6
|
-
|
|
19
|
+
extend ProcessorRegistry
|
|
20
|
+
self.error_label = 'output processor'
|
|
7
21
|
end
|
|
8
22
|
end
|
|
9
|
-
|
|
10
|
-
require "coradoc/output/adoc"
|
|
11
|
-
require "coradoc/output/coradoc_tree_debug"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'benchmark'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Coradoc
|
|
7
|
+
module PerformanceRegression
|
|
8
|
+
THRESHOLDS = {
|
|
9
|
+
markdown_parse_small: 2.0,
|
|
10
|
+
markdown_parse_medium: 3.0,
|
|
11
|
+
asciidoc_parse: 5.0,
|
|
12
|
+
html_serialize: 5.0,
|
|
13
|
+
md_to_html: 10.0,
|
|
14
|
+
adoc_to_html: 10.0,
|
|
15
|
+
core_model_creation: 1.0
|
|
16
|
+
}.freeze
|
|
17
|
+
|
|
18
|
+
BenchmarkResult = Struct.new(:name, :duration, :iterations, :threshold, keyword_init: true) do
|
|
19
|
+
def to_h
|
|
20
|
+
{ name:, duration:, iterations:, threshold:, passed: passed? }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def passed?
|
|
24
|
+
duration < threshold
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
ComparisonResult = Struct.new(:name, :duration, :baseline, keyword_init: true) do
|
|
29
|
+
def regressed?(pct = 0.2)
|
|
30
|
+
return false if baseline.nil? || baseline.zero?
|
|
31
|
+
|
|
32
|
+
(duration - baseline).abs / baseline > pct
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
def run_all(iterations: 3)
|
|
38
|
+
benchmarks = build_benchmarks
|
|
39
|
+
benchmarks.map do |name, threshold, block|
|
|
40
|
+
times = []
|
|
41
|
+
iterations.times { times << Benchmark.realtime { block.call } }
|
|
42
|
+
avg = times.sum / times.size
|
|
43
|
+
BenchmarkResult.new(name:, duration: avg, iterations:, threshold:)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def run_all_with_summary(iterations: 3)
|
|
48
|
+
results = run_all(iterations:)
|
|
49
|
+
failed = results.count { |r| !r.passed? }
|
|
50
|
+
{ results:, failed_count: failed, total: results.size }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def print_results(summary)
|
|
54
|
+
results = summary[:results]
|
|
55
|
+
results.each do |r|
|
|
56
|
+
status = r.passed? ? 'PASS' : 'FAIL'
|
|
57
|
+
puts " #{status} #{r.name}: #{r.duration.round(4)}s (threshold: #{r.threshold}s)"
|
|
58
|
+
end
|
|
59
|
+
puts
|
|
60
|
+
puts "#{summary[:total] - summary[:failed_count]}/#{summary[:total]} passed"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def compare_with_baseline(baseline_path, iterations: 3)
|
|
64
|
+
return [] unless File.exist?(baseline_path)
|
|
65
|
+
|
|
66
|
+
baseline_data = JSON.parse(File.read(baseline_path))
|
|
67
|
+
baseline_map = baseline_data.each_with_object({}) { |d, m| m[d['name']] = d['duration'] }
|
|
68
|
+
|
|
69
|
+
results = run_all(iterations:)
|
|
70
|
+
results.map do |r|
|
|
71
|
+
ComparisonResult.new(name: r.name, duration: r.duration, baseline: baseline_map[r.name])
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def build_benchmarks
|
|
78
|
+
sample = {
|
|
79
|
+
markdown_small: "# Title\n\n#{'Paragraph ' * 10}",
|
|
80
|
+
markdown_medium: "# Title\n\n#{'Content. ' * 100}\n\n## Section\n\n#{'More. ' * 100}",
|
|
81
|
+
asciidoc: "= Title\nAuthor\n\n== Section\n\n#{'Paragraph content. ' * 50}",
|
|
82
|
+
html_doc: Coradoc::CoreModel::DocumentElement.new(
|
|
83
|
+
title: 'Bench',
|
|
84
|
+
children: [
|
|
85
|
+
Coradoc::CoreModel::Block.new(element_type: 'paragraph', content: 'Test')
|
|
86
|
+
]
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
[
|
|
91
|
+
[:markdown_parse_small, THRESHOLDS[:markdown_parse_small],
|
|
92
|
+
-> { Coradoc::Markdown.parse(sample[:markdown_small]) }],
|
|
93
|
+
[:markdown_parse_medium, THRESHOLDS[:markdown_parse_medium],
|
|
94
|
+
-> { Coradoc::Markdown.parse(sample[:markdown_medium]) }],
|
|
95
|
+
[:asciidoc_parse, THRESHOLDS[:asciidoc_parse],
|
|
96
|
+
-> { Coradoc.parse(sample[:asciidoc], format: :asciidoc) }],
|
|
97
|
+
[:html_serialize, THRESHOLDS[:html_serialize],
|
|
98
|
+
-> { Coradoc::Html.serialize_static(sample[:html_doc]) }],
|
|
99
|
+
[:md_to_html, THRESHOLDS[:md_to_html],
|
|
100
|
+
-> { Coradoc.convert(sample[:markdown_small], from: :markdown, to: :html) }],
|
|
101
|
+
[:adoc_to_html, THRESHOLDS[:adoc_to_html],
|
|
102
|
+
-> { Coradoc.convert(sample[:asciidoc], from: :asciidoc, to: :html) }],
|
|
103
|
+
[:core_model_creation, THRESHOLDS[:core_model_creation],
|
|
104
|
+
-> { 1000.times { Coradoc::CoreModel::Block.new(element_type: 'paragraph', content: 'x') } }]
|
|
105
|
+
]
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Coradoc
|
|
4
|
+
# Module adapter that gives a module Registry-backed processor methods.
|
|
5
|
+
#
|
|
6
|
+
# Both Input and Output extend this module to get processor registration,
|
|
7
|
+
# lookup, and dispatch methods. All state is stored in a Registry instance.
|
|
8
|
+
#
|
|
9
|
+
# @api private
|
|
10
|
+
#
|
|
11
|
+
# @example
|
|
12
|
+
# module Input
|
|
13
|
+
# extend ProcessorRegistry
|
|
14
|
+
# self.error_label = "input processor"
|
|
15
|
+
# end
|
|
16
|
+
module ProcessorRegistry
|
|
17
|
+
def error_label=(label)
|
|
18
|
+
@error_label = label
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def registry
|
|
22
|
+
@registry ||= Registry.new(error_label: @error_label)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def define(processor, **options)
|
|
26
|
+
registry.define(processor, **options)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def get(id)
|
|
30
|
+
registry.get(id)
|
|
31
|
+
end
|
|
32
|
+
alias [] get
|
|
33
|
+
|
|
34
|
+
def registered?(id)
|
|
35
|
+
registry.registered?(id)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def processors
|
|
39
|
+
registry.items
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def for_file(filename)
|
|
43
|
+
registry.for_file(filename)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def process(content, options = {})
|
|
47
|
+
registry.process(content, options)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|