bashcov 4.0.2 → 4.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e79dc939af127bef6f99cd953e085033f167a5221e332a133951e476f9b63f6e
4
- data.tar.gz: 0aaf4dfc8062e7a14efa1b7ccfd1f2dc8ac7e86b53f79c31500019cfae3ab97d
3
+ metadata.gz: 4a96a6fc49f31d7d6ff999f03930dea2949276da0be7e72cada3a176a91170f9
4
+ data.tar.gz: c52cd9c108b691491cf35e6785421b624de4f1a05de19bfc2d7d3a18e21e1012
5
5
  SHA512:
6
- metadata.gz: f04d9cf50ddd7a95843676be55deb850201dea08ac7ef33bc6e7adfc17befe7e8ef14cc79a7899a2e529e058beea1930895344dfba915f6c3b8063f0faca5d49
7
- data.tar.gz: 43ff857b123ca2c5fa85bb03dc707ea4a52c0601bfc3eab1fc94863136298a12614315b2b369569c74071e97ab88525599780bbaa344a862d43a0b285c0da004
6
+ metadata.gz: 6330cc5bc8dcafadcf514903563cad2979ccd1078dcfad20ddd153a472041439cc26333890aa67ea1b96a713ba43a69b2d2551e3698d857e151d39699bd24370
7
+ data.tar.gz: e354fd7011ef79a3ef5a777b87542ce461f34084eb8a24cb2dc7e12986856a99581af492937ffd992490bf30742a6048a06b61128a0b914934ddb8f6c8bdf546
data/CHANGELOG.md CHANGED
@@ -1,7 +1,11 @@
1
- ## Unreleased ([changes](https://github.com/infertux/bashcov/compare/v4.0.2...master))
1
+ ## Unreleased ([changes](https://github.com/infertux/bashcov/compare/v4.0.3...master))
2
2
 
3
3
  * TBD
4
4
 
5
+ ## v4.0.3, 2026-11-11 ([changes](https://github.com/infertux/bashcov/compare/v4.0.2...v4.0.3))
6
+
7
+ * [BUGFIX] Do not read a closing quote after a space as a multiline string opener (fixes #118)
8
+
5
9
  ## v4.0.2, 2026-11-04 ([changes](https://github.com/infertux/bashcov/compare/v4.0.1...v4.0.2))
6
10
 
7
11
  * [BUGFIX] Keep xtrace writes blocking so coverage records are not dropped (fixes #113)
data/Gemfile.nix.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bashcov (4.0.2)
4
+ bashcov (4.0.3)
5
5
  simplecov (~> 1.1)
6
6
 
7
7
  GEM
data/flake.nix CHANGED
@@ -206,7 +206,7 @@
206
206
  pname = "bashcov";
207
207
  gemdir = self;
208
208
  lockfile = ./Gemfile.nix.lock;
209
- version = "4.0.2";
209
+ version = "4.0.3";
210
210
  postBuild = ''
211
211
  for gem in $out/${ruby.gemPath}/bundler/gems/*; do
212
212
  ln -sfrT "$gem" $out/${ruby.gemPath}/gems/"''${gem##*/}"
data/gemset.nix CHANGED
@@ -38,7 +38,7 @@
38
38
  path = ./.;
39
39
  type = "path";
40
40
  };
41
- version = "4.0.2";
41
+ version = "4.0.3";
42
42
  };
43
43
  benchmark = {
44
44
  groups = ["development"];
data/lib/bashcov/lexer.rb CHANGED
@@ -34,9 +34,27 @@ module Bashcov
34
34
  # line continuation (but never after an unescaped newline) - this must
35
35
  # come before simple line continuations which would claim the opening
36
36
  # line otherwise - unlike single quotes, double quotes may contain escaped
37
- # characters such as \"
38
- *[false, true].product([["'", /[^']*/], ['"', /(?:[^"\\]|\\.)*/m]]).map do |forward, (char, body)|
39
- [/\G[^\n]+(?:[ \t=]|\\\n[ \t]*)+#{char}#{body}#{char}/m, forward]
37
+ # characters such as \" - the opening quote must not close a string
38
+ # already open on its line (e.g. `printf '%s: ' "$1"`), so the text
39
+ # before it may only hold complete strings, plus lone quotes of the other
40
+ # kind which may nest in command substitutions, e.g. "$(a 'b')" - this
41
+ # text may only be empty right after the closing quote of another string
42
+ *[false, true].product(["'", '"']).map do |forward, char|
43
+ # complete double-quoted string on one line, command substitutions
44
+ # being free to hold other strings, e.g. "$(a "b")"
45
+ dq = /(?<dq>"(?>(?:[^"\\\n$]|\\[^\n]|\$(?!\()|\$(?<sub>\((?>(?:[^()'"\\\n]|\\[^\n]|'[^'\n]*'|\g<dq>|\g<sub>)*)\)))*)")/
46
+ other = (char == "'" ? '(?!\g<dq>)"' : %q{(?!'[^'\n]*')'})
47
+ prefix = /(?:[^\n'"\\]|\\[^\n]|'[^'\n]*'|#{dq}|#{other})+|(?<=['"])/
48
+ body =
49
+ if char == "'"
50
+ /[^']*/
51
+ else
52
+ # same as above over several lines, or failing that anything up
53
+ # to the next unescaped quote
54
+ /(?<mdq>(?>(?:[^"\\$]|\\.|\$(?!\()|\$(?<msub>\((?>(?:[^()'"\\]|\\.|'[^']*'|"\g<mdq>"|\g<msub>)*)\)))*))|(?>(?:[^"\\]|\\.)*)/m
55
+ end
56
+
57
+ [/\G(?:#{prefix})(?:[ \t=]|\\\n[ \t]*)+#{char}(?:#{body})#{char}/m, forward]
40
58
  end,
41
59
 
42
60
  # simple line continuations with backslashes
@@ -61,23 +79,28 @@ module Bashcov
61
79
  offsets = lines.each_with_object([0]) { |line, memo| memo << (memo.last + line.size) }
62
80
 
63
81
  lineno = 0
82
+ resume = nil
64
83
  while lineno < lines.size
65
84
  # skip ahead past a multiline construct once its lines are marked, but
66
- # recheck its last line as it may open another one, e.g. `a'; b='`
67
- last = mark_multilines(content, offsets[lineno], lineno) || lineno
85
+ # recheck its last line as it may open another one, e.g. `a'; b='` -
86
+ # look right after a construct ending mid-line first, so that its
87
+ # closing quote is not read as an opener, then recheck the whole line
88
+ last, stop = (resume && mark_multilines(content, resume, lineno)) || mark_multilines(content, offsets[lineno], lineno)
89
+ last ||= lineno
68
90
  lineno.upto(last) { |sub_lineno| mark_line(lines[sub_lineno], sub_lineno) }
91
+ resume = (stop if last > lineno && stop < content.size && content[stop] != $/)
69
92
  lineno = (last > lineno ? last : last + 1)
70
93
  end
71
94
  end
72
95
 
73
96
  private
74
97
 
75
- # @return [Integer, nil] last line of the multiline construct starting at
76
- # +lineno+, if any
98
+ # @return [Array<Integer>, nil] last line and end offset of the multiline
99
+ # construct starting at +offset+ on +lineno+, if any
77
100
  def mark_multilines(content, offset, lineno)
78
101
  MULTILINE_PATTERNS.each do |regexp, forward|
79
- last = mark_multiline(content, offset, lineno, regexp, forward: forward)
80
- return last if last
102
+ result = mark_multiline(content, offset, lineno, regexp, forward: forward)
103
+ return result if result
81
104
  end
82
105
 
83
106
  nil
@@ -107,7 +130,7 @@ module Bashcov
107
130
  @coverage[sub_lineno] ||= @coverage[reference_lineno]
108
131
  end
109
132
 
110
- last if length.positive?
133
+ [last, multiline_match.end(0)] if length.positive?
111
134
  end
112
135
 
113
136
  def mark_line(line, lineno)
@@ -3,5 +3,5 @@
3
3
  # :nodoc:
4
4
  module Bashcov
5
5
  # Current Bashcov version
6
- VERSION = "4.0.2"
6
+ VERSION = "4.0.3"
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bashcov
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.2
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cédric Félizard