Module: Ryac::Pipeline::SourcePatcher
- Included in:
- Minifier, Stage, StageRunner
- Defined in:
- lib/ryac/pipeline/source_patcher.rb,
sig/ryac/pipeline/source_patcher.rbs
Instance Method Summary collapse
-
#apply_patches(source, patches) ⇒ String
The one patch applier: every stage splices byte patches through here.
- #mk(node, replacement) ⇒ { start: Integer, end: Integer, replacement: String }
-
#src(source, node) ⇒ String
byteslice is typed String? but node offsets always lie inside the source the node was parsed from, so the result is never nil.
-
#verify_parses(text, label) ⇒ void
The output of every pipeline permutation must at minimum be valid Ruby.
Instance Method Details
#apply_patches(source, patches) ⇒ String
The one patch applier: every stage splices byte patches through here. Patches must be disjoint — an overlap means two rewrites fought over the same bytes, and applying either order silently corrupts the output, so it raises with both patches named. The end-position tie-break keeps same-start insertions deterministic.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/ryac/pipeline/source_patcher.rb', line 17 def apply_patches(source, patches) return source if patches.none? sorted = patches.sort_by { |p| [-p[:start], -p[:end]] } sorted.each_cons(2) do |after, before| # each_cons(2) yields only full pairs; the destructuring alone is # what makes the elements look nilable. # @type var after: { start: Integer, end: Integer, replacement: String } # @type var before: { start: Integer, end: Integer, replacement: String } if before[:end] > after[:start] raise MinifyError, "overlapping patches: #{before.inspect} / #{after.inspect}" end end result = source.b.dup sorted.each do |patch| result[patch[:start]...patch[:end]] = patch[:replacement].b end result.force_encoding(source.encoding) end |
#mk(node, replacement) ⇒ { start: Integer, end: Integer, replacement: String }
8 9 10 |
# File 'lib/ryac/pipeline/source_patcher.rb', line 8 def mk(node, replacement) { start: node.location.start_offset, end: node.location.end_offset, replacement: replacement } end |
#src(source, node) ⇒ String
byteslice is typed String? but node offsets always lie inside the source the node was parsed from, so the result is never nil.
38 39 40 |
# File 'lib/ryac/pipeline/source_patcher.rb', line 38 def src(source, node) # steep:ignore MethodBodyTypeMismatch source.byteslice(node.location.start_offset, node.location.length) end |
#verify_parses(text, label) ⇒ void
This method returns an undefined value.
The output of every pipeline permutation must at minimum be valid Ruby. Prism also rejects duplicated parameter names, so a rename that collides inside a signature is caught here, at the stage that produced it.
46 47 48 49 50 51 |
# File 'lib/ryac/pipeline/source_patcher.rb', line 46 def verify_parses(text, label) return if text.empty? errors = Prism.parse(text).errors raise InvalidOutputError.new(label, errors) unless errors.empty? end |