coradoc 2.0.21 → 2.0.22

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.
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ # Include resolver protocol.
5
+ #
6
+ # A resolver is anything that responds to +#call(target:, base_dir:,
7
+ # options:, context:)+ and returns the raw bytes of the included
8
+ # target, BEFORE tag/line/indent selectors are applied. Selectors
9
+ # live in the processor; the resolver only fetches bytes.
10
+ #
11
+ # The default resolver is {IncludeResolver::Filesystem}. Custom
12
+ # resolvers (HTTP, database, generated) plug in here without changes
13
+ # to the processor (OCP).
14
+ #
15
+ # Contract:
16
+ # call(target:, base_dir:, options:, context:) -> String
17
+ # target String path/URL as authored
18
+ # base_dir String absolute path to the including file's dir
19
+ # options CoreModel::IncludeOptions
20
+ # context Hash recursion state (depth, parent_chain, ...)
21
+ #
22
+ # Raises Coradoc::IncludeNotFoundError if the target cannot be located.
23
+ # The processor's missing-file policy decides what to do with that.
24
+ #
25
+ # This base class is provided for documentation and for is_a? checks.
26
+ # Custom resolvers do NOT need to inherit — duck typing on the call
27
+ # signature is sufficient. ( SPEC 13 uses a bare Object with
28
+ # define_singleton_method, which we support.)
29
+ class IncludeResolver
30
+ autoload :Filesystem, "#{__dir__}/include_resolver/filesystem"
31
+
32
+ def call(target:, base_dir:, options:, context:)
33
+ raise NotImplementedError,
34
+ "#{self.class} must implement #call(target:, base_dir:, options:, context:)"
35
+ end
36
+
37
+ class << self
38
+ # Coerce +value+ into something that quacks like an IncludeResolver.
39
+ # - Already-callable objects (respond to :call) are returned as-is.
40
+ # - Symbols are interpreted as built-in names: +:filesystem+,
41
+ # +:filesystem_strict+ (path-traversal protection on).
42
+ #
43
+ # @param value [Object, nil] the resolver or built-in name
44
+ # @param base_dir [String] required for built-in filesystem resolvers
45
+ # @param allow_unsafe [Boolean] opt-out of path-traversal protection
46
+ # @return [Object] something callable as a resolver
47
+ def coerce(value, base_dir:, allow_unsafe: false)
48
+ return Filesystem.new(base_dir: base_dir, allow_unsafe: allow_unsafe) if value.nil?
49
+
50
+ case value
51
+ when Symbol then coerce_symbol(value, base_dir: base_dir, allow_unsafe: allow_unsafe)
52
+ else value
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def coerce_symbol(name, base_dir:, allow_unsafe:)
59
+ case name
60
+ when :filesystem then Filesystem.new(base_dir: base_dir, allow_unsafe: allow_unsafe)
61
+ else
62
+ raise ArgumentError, "Unknown include resolver: #{name.inspect}"
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module IncludeSelectors
5
+ # Indent normalization. Two modes per asciidoctor:
6
+ #
7
+ # indent=0 strip all leading whitespace from every line
8
+ # indent=N normalize leading whitespace to exactly N spaces
9
+ # nil pass through unchanged
10
+ module Indent
11
+ # @param text [String]
12
+ # @param options [Coradoc::CoreModel::IncludeOptions]
13
+ # @return [String]
14
+ def self.call(text, options:)
15
+ return text if options.indent.nil?
16
+
17
+ if options.indent.zero?
18
+ strip_all(text)
19
+ else
20
+ reindent(text, options.indent)
21
+ end
22
+ end
23
+
24
+ class << self
25
+ private
26
+
27
+ def strip_all(text)
28
+ text.lines.map { |line| line.sub(/\A[[:space:]]+/, '') }.join
29
+ end
30
+
31
+ def reindent(text, target)
32
+ min_indent = text.lines
33
+ .reject { |l| l.strip.empty? }
34
+ .map { |l| l.length - l.lstrip.length }
35
+ .min || 0
36
+
37
+ pad = ' ' * target
38
+ text.lines.map do |line|
39
+ stripped = strip_common_prefix(line, min_indent)
40
+ if stripped.strip.empty?
41
+ stripped.strip + "\n"
42
+ else
43
+ pad + stripped
44
+ end
45
+ end.join
46
+ end
47
+
48
+ def strip_common_prefix(line, count)
49
+ line.sub(/\A[[:space:]]{0,#{count}}/, '')
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module IncludeSelectors
5
+ # Shifts section heading levels in a parsed CoreModel subtree.
6
+ #
7
+ # Applied AFTER parsing — works on SectionElement instances. Two modes:
8
+ #
9
+ # relative (+N / -N) every SectionElement#level += delta
10
+ # absolute (N) the FIRST section's level becomes N, and
11
+ # descendants shift by the same delta so their
12
+ # relative structure is preserved (asciidoctor
13
+ # behavior).
14
+ #
15
+ # The processor passes a freshly-parsed subtree to this selector, so
16
+ # there are no external references and in-place mutation is safe.
17
+ module LevelOffset
18
+ # @param core [Coradoc::CoreModel::Base] freshly parsed — mutated
19
+ # @param options [Coradoc::CoreModel::IncludeOptions]
20
+ # @return [Coradoc::CoreModel::Base] the same core (mutated)
21
+ def self.call(core, options:)
22
+ offset = options.leveloffset
23
+ return core if offset.nil?
24
+
25
+ first_level = find_first_level(core)
26
+ actual_delta = compute_actual_delta(offset, first_level)
27
+ return core if actual_delta.zero?
28
+
29
+ walk_and_shift(core, actual_delta)
30
+ core
31
+ end
32
+
33
+ class << self
34
+ private
35
+
36
+ def compute_actual_delta(offset, first_level)
37
+ case offset.mode
38
+ when 'relative' then offset.delta
39
+ when 'absolute'
40
+ return 0 if first_level.nil?
41
+
42
+ offset.delta - first_level
43
+ else 0
44
+ end
45
+ end
46
+
47
+ def find_first_level(node)
48
+ case node
49
+ when Coradoc::CoreModel::SectionElement
50
+ node.level || 1
51
+ when Coradoc::CoreModel::StructuralElement, Coradoc::CoreModel::Block
52
+ walk_for_first_level(node.children)
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ def walk_for_first_level(children)
59
+ return nil if children.nil?
60
+
61
+ children.each do |child|
62
+ lvl = find_first_level(child)
63
+ return lvl unless lvl.nil?
64
+ end
65
+ nil
66
+ end
67
+
68
+ def walk_and_shift(node, delta)
69
+ case node
70
+ when Coradoc::CoreModel::SectionElement
71
+ node.level = [(node.level || 1) + delta, 0].max
72
+ walk_children(node, delta)
73
+ when Coradoc::CoreModel::StructuralElement, Coradoc::CoreModel::Block
74
+ walk_children(node, delta)
75
+ end
76
+ end
77
+
78
+ def walk_children(node, delta)
79
+ return if node.children.nil?
80
+
81
+ node.children.each { |c| walk_and_shift(c, delta) }
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module IncludeSelectors
5
+ # Line-range selection. Parses asciidoctor-style specs:
6
+ #
7
+ # N single line
8
+ # A..B inclusive range
9
+ # A..B;C;D..E multiple, semicolon-separated
10
+ #
11
+ # Out-of-bounds clamps gracefully (SPEC 3.4). One-based indexing
12
+ # (asciidoctor convention).
13
+ module Lines
14
+ SPEC_PART = %r{
15
+ \A
16
+ (?<start>\d+)
17
+ (?:\.\.(?<finish>\d+))?
18
+ \z
19
+ }x.freeze
20
+
21
+ # @param text [String]
22
+ # @param options [Coradoc::CoreModel::IncludeOptions]
23
+ # @return [String]
24
+ def self.call(text, options:)
25
+ return text unless options.lines?
26
+
27
+ ranges = parse_spec(options.lines_spec, max: text.lines.length)
28
+ return '' if ranges.empty?
29
+
30
+ indices = ranges.flat_map { |start, finish| (start..finish).to_a }.uniq.sort
31
+ text.lines.values_at(*indices.map { |i| i - 1 }).join
32
+ end
33
+
34
+ class << self
35
+ private
36
+
37
+ def parse_spec(spec, max:)
38
+ spec.split(';').map(&:strip).filter_map do |part|
39
+ parse_part(part, max: max)
40
+ end
41
+ end
42
+
43
+ def parse_part(part, max:)
44
+ SPEC_PART.match(part) do |m|
45
+ start = m[:start].to_i
46
+ finish = m[:finish] ? m[:finish].to_i : start
47
+ [start, finish].minmax.map { |n| clamp(n, max: max) }
48
+ end
49
+ end
50
+
51
+ def clamp(n, max:)
52
+ return nil if n < 1
53
+ return max if n > max
54
+
55
+ n
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module IncludeSelectors
5
+ # Extracts regions delimited by +// tag::name[]+ / +// end::name[]+
6
+ # markers from included content. Supports single, multiple,
7
+ # wildcard (*), and inverted (**) selection.
8
+ #
9
+ # Tag markers themselves are never emitted as text (SPEC 2.8).
10
+ # Unknown tag names yield empty content (SPEC 2.6). Nested tag
11
+ # regions are included when an outer tag is selected (SPEC 2.7).
12
+ #
13
+ # Marker forms recognized:
14
+ # // tag::name[] (AsciiDoc line comment)
15
+ # ## tag::name[] (Markdown line comment, permissive)
16
+ #
17
+ # Markers may appear on their own line; they must be the first
18
+ # non-whitespace token on that line (asciidoctor convention).
19
+ module Tags
20
+ MARKER_OPEN = /\A[[:space:]]*(?:\/\/+|#+)[[:space:]]*tag::([^\[\]]+)\[[[:space:]]*\]/
21
+ MARKER_CLOSE = /\A[[:space:]]*(?:\/\/+|#+)[[:space:]]*end::([^\[\]]+)\[[[:space:]]*\]/
22
+
23
+ # @param text [String] raw included file content
24
+ # @param options [Coradoc::CoreModel::IncludeOptions]
25
+ # @return [String] filtered content
26
+ def self.call(text, options:)
27
+ return text unless options.tags?
28
+
29
+ if options.tags_inverted
30
+ inverted(text)
31
+ elsif options.tags_wildcard
32
+ wildcard(text)
33
+ else
34
+ named(text, options.tags)
35
+ end
36
+ end
37
+
38
+ class << self
39
+ private
40
+
41
+ def scan_markers(text)
42
+ markers = []
43
+ text.each_line.with_index do |line, idx|
44
+ if (m = MARKER_OPEN.match(line))
45
+ markers << [:open, m[1].strip, idx]
46
+ elsif (m = MARKER_CLOSE.match(line))
47
+ markers << [:close, m[1].strip, idx]
48
+ end
49
+ end
50
+ markers
51
+ end
52
+
53
+ def named(text, names)
54
+ wanted_indices = selected_line_indices(text, names).to_set
55
+ pick_lines(text, wanted_indices)
56
+ end
57
+
58
+ def selected_line_indices(text, wanted_names)
59
+ markers = scan_markers(text)
60
+ wanted = wanted_names.to_set
61
+ open_stack = []
62
+ emit = {}
63
+
64
+ markers.each do |kind, name, idx|
65
+ case kind
66
+ when :open
67
+ next unless wanted.include?(name)
68
+
69
+ open_stack.push([name, idx])
70
+ when :close
71
+ next unless wanted.include?(name)
72
+
73
+ open_idx = open_stack.rindex { |n, _| n == name }
74
+ next unless open_idx
75
+
76
+ _open_name, open_line = open_stack.delete_at(open_idx)
77
+ (open_line + 1...idx).each { |i| emit[i] = true }
78
+ end
79
+ end
80
+
81
+ emit.keys
82
+ end
83
+
84
+ def wildcard(text)
85
+ markers = scan_markers(text)
86
+ open_stack = []
87
+ emit = {}
88
+
89
+ markers.each do |kind, _name, idx|
90
+ case kind
91
+ when :open
92
+ open_stack.push(idx)
93
+ when :close
94
+ next if open_stack.empty?
95
+
96
+ open_line = open_stack.pop
97
+ (open_line + 1...idx).each { |i| emit[i] = true }
98
+ end
99
+ end
100
+
101
+ pick_lines(text, emit.keys.to_set)
102
+ end
103
+
104
+ def inverted(text)
105
+ markers = scan_markers(text)
106
+ open_stack = []
107
+ excluded = {}
108
+
109
+ markers.each do |kind, _name, idx|
110
+ case kind
111
+ when :open
112
+ open_stack.push(idx)
113
+ when :close
114
+ next if open_stack.empty?
115
+
116
+ open_line = open_stack.pop
117
+ (open_line..idx).each { |i| excluded[i] = true }
118
+ end
119
+ end
120
+
121
+ markers.each { |_kind, _name, idx| excluded[idx] = true }
122
+
123
+ lines = text.lines
124
+ kept = lines.each_with_index.reject { |_line, idx| excluded[idx] }
125
+ kept.map(&:first).join
126
+ end
127
+
128
+ def pick_lines(text, wanted_indices)
129
+ lines = text.lines
130
+ lines.each_with_index.select { |_line, idx| wanted_indices.include?(idx) }
131
+ .map(&:first).join
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ require 'set'
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ # Pure-function selectors applied to resolved include content.
5
+ #
6
+ # Each selector owns exactly one transformation (MECE):
7
+ # Tags // tag::X[] ... // end::X[] region extraction
8
+ # Lines line-range selection (1..N;2;3..4)
9
+ # Indent leading-whitespace normalization
10
+ # LevelOffset section-level shift (applied AFTER parsing)
11
+ #
12
+ # Tags, Lines, and Indent take a String and return a String.
13
+ # LevelOffset takes a parsed CoreModel and returns a new CoreModel.
14
+ #
15
+ # The processor orchestrates the order:
16
+ # 1. Tags (or Lines; Lines wins if both specified — SPEC 3.5)
17
+ # 2. Indent
18
+ # 3. parse → CoreModel
19
+ # 4. LevelOffset
20
+ module IncludeSelectors
21
+ autoload :Tags, "#{__dir__}/include_selectors/tags"
22
+ autoload :Lines, "#{__dir__}/include_selectors/lines"
23
+ autoload :Indent, "#{__dir__}/include_selectors/indent"
24
+ autoload :LevelOffset, "#{__dir__}/include_selectors/level_offset"
25
+ end
26
+ end
@@ -0,0 +1,202 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ # Flat-mode include processor — the explicit "flatten" step.
5
+ #
6
+ # Walks a parsed CoreModel and expands every {CoreModel::Include} link
7
+ # node into the parsed content of its target, recursing into the result.
8
+ # The original CoreModel is NOT modified — a new subtree is constructed
9
+ # and spliced into place.
10
+ #
11
+ # Invoked via the public API +Coradoc.resolve_includes(doc, base_dir:)+.
12
+ # Callers control resolution strategy (filesystem, HTTP, custom),
13
+ # missing-include policy, recursion depth, and path-traversal safety.
14
+ #
15
+ # Honors:
16
+ # - +missing_include+ policy: :error (default) | :warn | :silent | :passthrough
17
+ # - +max_depth+ limit (raises Coradoc::IncludeDepthExceededError)
18
+ # - circular detection (raises Coradoc::CircularIncludeError)
19
+ # - tags/lines/indent selectors (applied to raw text before parse)
20
+ # - leveloffset selector (applied to parsed CoreModel)
21
+ # - +base_dir+ re-rooting (recursive includes resolve relative to
22
+ # the including file — SPEC 7.2)
23
+ class ResolveIncludes
24
+ DEFAULT_MAX_DEPTH = 64
25
+
26
+ class << self
27
+ def call(core, resolver:, base_dir:, **opts)
28
+ new(resolver: resolver, base_dir: base_dir, **opts).call(core)
29
+ end
30
+ end
31
+
32
+ # @param resolver [#call] anything responding to +#call(target:, base_dir:, options:, context:)+
33
+ # @param base_dir [String] absolute path to the document root directory
34
+ # @param missing_include [Symbol] :error | :warn | :silent | :passthrough
35
+ # @param max_depth [Integer] recursion cap
36
+ # @param parse_format [Symbol] format to use when re-parsing included content
37
+ def initialize(resolver:, base_dir:,
38
+ missing_include: :error,
39
+ max_depth: DEFAULT_MAX_DEPTH,
40
+ parse_format: :asciidoc)
41
+ @resolver = Coradoc::IncludeResolver.coerce(resolver, base_dir: base_dir)
42
+ @base_dir = base_dir
43
+ @missing_policy = missing_include
44
+ @max_depth = max_depth
45
+ @parse_format = parse_format
46
+ end
47
+
48
+ # Walk + transform. Returns a NEW CoreModel with includes expanded.
49
+ def call(core)
50
+ expand_node(core, base_dir: File.expand_path(@base_dir), chain: [], depth: 0)
51
+ end
52
+
53
+ private
54
+
55
+ def expand_node(node, base_dir:, chain:, depth:)
56
+ return node unless node.is_a?(Coradoc::CoreModel::Base)
57
+
58
+ case node
59
+ when Coradoc::CoreModel::Include
60
+ expand_include(node, base_dir: base_dir, chain: chain, depth: depth)
61
+ when Coradoc::CoreModel::StructuralElement, Coradoc::CoreModel::Block
62
+ expand_container(node, base_dir: base_dir, chain: chain, depth: depth)
63
+ else
64
+ node
65
+ end
66
+ end
67
+
68
+ def expand_container(node, base_dir:, chain:, depth:)
69
+ return node if node.children.nil? || node.children.empty?
70
+
71
+ expanded_children = node.children.flat_map do |child|
72
+ expanded = expand_node(child, base_dir: base_dir, chain: chain, depth: depth)
73
+ Array(expanded)
74
+ end
75
+
76
+ return node if expanded_children.equal?(node.children) || same_children?(expanded_children, node.children)
77
+
78
+ duplicate_with_children(node, expanded_children)
79
+ end
80
+
81
+ # The processor must not mutate its input. Each container that has
82
+ # expanded includes is replaced by a shallow copy with a new
83
+ # +children+ array — the original document tree stays intact so the
84
+ # caller can re-resolve with different options.
85
+ def duplicate_with_children(node, new_children)
86
+ duplicate = node.dup
87
+ duplicate.children = new_children
88
+ duplicate
89
+ end
90
+
91
+ def same_children?(expanded, original)
92
+ return false unless expanded.length == original.length
93
+
94
+ expanded.each_with_index.all? { |node, i| node.equal?(original[i]) }
95
+ end
96
+
97
+ def expand_include(include_node, base_dir:, chain:, depth:)
98
+ enforce_depth!(include_node, depth)
99
+ enforce_cycle!(include_node, base_dir: base_dir, chain: chain)
100
+
101
+ target = include_node.target
102
+ new_chain = chain + [resolve_target_path(target, base_dir)]
103
+
104
+ content = fetch_content(include_node, base_dir: base_dir)
105
+ return replacement_for_missing(include_node) if missing_content?(content)
106
+
107
+ applied = apply_text_selectors(content, include_node.options)
108
+ parsed = parse_included(applied)
109
+
110
+ shifted = Coradoc::IncludeSelectors::LevelOffset.call(parsed, options: include_node.options)
111
+
112
+ new_base_dir = File.dirname(resolve_target_path(target, base_dir))
113
+ expand_subtree(shifted, base_dir: new_base_dir, chain: new_chain, depth: depth + 1)
114
+ end
115
+
116
+ def missing_content?(content)
117
+ content.nil? || content == :passthrough
118
+ end
119
+
120
+ def fetch_content(include_node, base_dir:)
121
+ @resolver.call(
122
+ target: include_node.target,
123
+ base_dir: base_dir,
124
+ options: include_node.options,
125
+ context: {}
126
+ )
127
+ rescue Coradoc::IncludeNotFoundError => e
128
+ handle_missing(include_node, e)
129
+ end
130
+
131
+ def handle_missing(include_node, error)
132
+ case @missing_policy
133
+ when :error then raise error
134
+ when :warn
135
+ Coradoc::Logger.warn("Include target not found: #{include_node.target}")
136
+ nil
137
+ when :silent then nil
138
+ when :passthrough then :passthrough
139
+ else raise error
140
+ end
141
+ end
142
+
143
+ def replacement_for_missing(include_node)
144
+ return [include_node] if @missing_policy == :passthrough
145
+
146
+ []
147
+ end
148
+
149
+ def apply_text_selectors(text, options)
150
+ text = apply_lines_or_tags(text, options)
151
+ Coradoc::IncludeSelectors::Indent.call(text, options: options)
152
+ end
153
+
154
+ def apply_lines_or_tags(text, options)
155
+ # lines wins when both specified (SPEC 3.5)
156
+ return Coradoc::IncludeSelectors::Lines.call(text, options: options) if options.lines?
157
+
158
+ Coradoc::IncludeSelectors::Tags.call(text, options: options)
159
+ end
160
+
161
+ def parse_included(text)
162
+ return empty_core if text.nil? || text.empty?
163
+
164
+ Coradoc.parse(text, format: @parse_format)
165
+ end
166
+
167
+ def empty_core
168
+ Coradoc::CoreModel::DocumentElement.new
169
+ end
170
+
171
+ def expand_subtree(core, base_dir:, chain:, depth:)
172
+ expanded = expand_node(core, base_dir: base_dir, chain: chain, depth: depth)
173
+ return [expanded] unless expanded.is_a?(Coradoc::CoreModel::StructuralElement)
174
+
175
+ expanded.children || []
176
+ end
177
+
178
+ def enforce_depth!(include_node, depth)
179
+ return if depth < @max_depth
180
+
181
+ raise Coradoc::IncludeDepthExceededError.new(
182
+ target: include_node.target,
183
+ depth: depth,
184
+ max: @max_depth
185
+ )
186
+ end
187
+
188
+ def enforce_cycle!(include_node, base_dir:, chain:)
189
+ full = resolve_target_path(include_node.target, base_dir)
190
+ return unless chain.include?(full)
191
+
192
+ raise Coradoc::CircularIncludeError.new(
193
+ target: include_node.target,
194
+ chain: chain
195
+ )
196
+ end
197
+
198
+ def resolve_target_path(target, base_dir)
199
+ File.expand_path(target, base_dir)
200
+ end
201
+ end
202
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Coradoc
4
- VERSION = '2.0.21'
4
+ VERSION = '2.0.22'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coradoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.21
4
+ version: 2.0.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -73,11 +73,16 @@ files:
73
73
  - lib/coradoc/core_model/frontmatter.rb
74
74
  - lib/coradoc/core_model/frontmatter/codec.rb
75
75
  - lib/coradoc/core_model/frontmatter/field_transform.rb
76
+ - lib/coradoc/core_model/frontmatter/frontmatter_value.rb
76
77
  - lib/coradoc/core_model/frontmatter/schema_resolver.rb
77
78
  - lib/coradoc/core_model/frontmatter/text_splitter.rb
79
+ - lib/coradoc/core_model/has_children.rb
78
80
  - lib/coradoc/core_model/horizontal_rule_block.rb
79
81
  - lib/coradoc/core_model/id_generator.rb
80
82
  - lib/coradoc/core_model/image.rb
83
+ - lib/coradoc/core_model/include.rb
84
+ - lib/coradoc/core_model/include_level_offset.rb
85
+ - lib/coradoc/core_model/include_options.rb
81
86
  - lib/coradoc/core_model/inline_element.rb
82
87
  - lib/coradoc/core_model/list_block.rb
83
88
  - lib/coradoc/core_model/list_item.rb
@@ -104,6 +109,13 @@ files:
104
109
  - lib/coradoc/errors.rb
105
110
  - lib/coradoc/format_module.rb
106
111
  - lib/coradoc/hooks.rb
112
+ - lib/coradoc/include_resolver.rb
113
+ - lib/coradoc/include_resolver/filesystem.rb
114
+ - lib/coradoc/include_selectors.rb
115
+ - lib/coradoc/include_selectors/indent.rb
116
+ - lib/coradoc/include_selectors/level_offset.rb
117
+ - lib/coradoc/include_selectors/lines.rb
118
+ - lib/coradoc/include_selectors/tags.rb
107
119
  - lib/coradoc/input.rb
108
120
  - lib/coradoc/logger.rb
109
121
  - lib/coradoc/output.rb
@@ -111,6 +123,7 @@ files:
111
123
  - lib/coradoc/processor_registry.rb
112
124
  - lib/coradoc/query.rb
113
125
  - lib/coradoc/registry.rb
126
+ - lib/coradoc/resolve_includes.rb
114
127
  - lib/coradoc/serializer/registry.rb
115
128
  - lib/coradoc/transform.rb
116
129
  - lib/coradoc/transform/base.rb