simple_english 0.10.0-aarch64-linux → 0.11.0-aarch64-linux

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: 0ebf2662378b400619f748fc25522c548682a96ebdd3a0b72fea03d3f52a6489
4
- data.tar.gz: 5d6b4b81d24f7a4ff5c27393c5cbe5cd4c2339b4aa14c2ab021c6d25060a190b
3
+ metadata.gz: dd3dbf80f63e4a6586d0c1b9ab24cd843994cbac8e73927cf2a7242d030b9d31
4
+ data.tar.gz: dab8d658d20ab00c39d44a7610fc20cb020ef86c222ec3d1e05c281a7d569e6d
5
5
  SHA512:
6
- metadata.gz: b4ab7d8ab283bded33454e049dafba66694c9b67bf014b5288379e6b00b86716326958e280b5172922f4fefc467b2c3021ad1b8ce49a4e9128e0c88a9589beb6
7
- data.tar.gz: 1430067f026c0aa5d4e5ba4e5344d86d3ef7f4a9f06be94df8c4722eee44e41d163f33cc7245acbda33c6ee16aedde4d4d520b7bdd77dabb3fed499bce8eb43e
6
+ metadata.gz: 6671ad97fa056f5a1714ce074a146823a45b0b554ac0252dda25f7d1d037c411a3e7e572ea51303a6345a0d62b80065bc24c855527285ae07cc96b77fd7b1af0
7
+ data.tar.gz: 06e1f94e2e0c904861713691e0d62d3f21a8d975593244e7a6acd1e19ade0612b0e536436e614ab61aecd431f21e68c1437ba03403eee35d940c912af64d0b74
data/README.md CHANGED
@@ -133,29 +133,59 @@ se mcp
133
133
 
134
134
  ### CI
135
135
 
136
- Gate the prose in the pull request that changes it. The plain run
137
- fails the build on findings, and the SARIF report puts them inline:
136
+ Gate the pull request's prose in GitHub Actions. The lint fails the build on findings:
138
137
 
139
138
  ```yaml
140
139
  name: lint-docs
141
140
  on: [pull_request]
142
- permissions:
143
- security-events: write
144
141
  jobs:
145
142
  lint:
146
143
  runs-on: ubuntu-latest
147
144
  steps:
148
145
  - uses: actions/checkout@v7
149
- - uses: ruby/setup-ruby@v1
150
- - run: gem install simple_english
151
- - run: se --format sarif . > lint.sarif
152
- - run: se .
146
+ - uses: TonyCTHsu/simple-english@v0.11.0
147
+ with:
148
+ files: |
149
+ docs/
150
+ README.md
151
+ ```
152
+
153
+ To see the findings inline in the pull request, lint with
154
+ `format: sarif` and upload the report. Add
155
+ `permissions: {security-events: write}` to the workflow:
156
+
157
+ ```yaml
158
+ - uses: TonyCTHsu/simple-english@v0.11.0
159
+ with:
160
+ format: sarif
153
161
  - uses: github/codeql-action/upload-sarif@v3
154
162
  with:
155
- sarif_file: lint.sarif
163
+ sarif_file: simple-english.sarif
156
164
  if: always()
157
165
  ```
158
166
 
167
+ Any CI can run the lint. Install the gem, run `se lint .`, and fail the
168
+ build on exit code 1.
169
+
170
+ ### Git hooks
171
+
172
+ Install the gem once, then wire your hook runner. The command to run
173
+ is `se lint`.
174
+
175
+ #### Pre-commit framework
176
+
177
+ ```yaml
178
+ # .pre-commit-config.yaml
179
+ repos:
180
+ - repo: https://github.com/TonyCTHsu/simple-english
181
+ rev: v0.11.0
182
+ hooks:
183
+ - id: se-lint
184
+ ```
185
+
186
+ For Husky with lint-staged, map every staged file to `se lint`. For
187
+ Lefthook, run `se lint {staged_files}` in a `pre-commit` command.
188
+
159
189
  ## Config and suppressions
160
190
 
161
191
  ### Config file
data/docs/RULES.md CHANGED
@@ -50,7 +50,7 @@ Use the simple past. Say when it happened.
50
50
 
51
51
  ### SE_ING_AFTER_COMMA: No -ing after a comma
52
52
 
53
- Start a new sentence instead of the -ing phrase.
53
+ Write a new sentence, or put the condition first. A trailing -ing phrase hides who does what and when.
54
54
 
55
55
  - Wrong: The tool runs, making it easy.
56
56
  - Right: The tool runs. It is easy.
@@ -14,6 +14,7 @@ require "net/http"
14
14
  require "uri"
15
15
 
16
16
  require_relative "../lint/plain_text"
17
+ require_relative "../lint/utf16"
17
18
 
18
19
  module SimpleEnglish
19
20
  module LanguageTool
@@ -71,25 +72,16 @@ module SimpleEnglish
71
72
  end
72
73
 
73
74
  def utf16_slice(text, offset, length)
74
- first = utf16_index(text, offset)
75
- last = utf16_index(text, offset + length)
75
+ first = UTF16.index(text, offset)
76
+ last = UTF16.index(text, offset + length)
76
77
  text[first...last]
77
78
  end
78
79
 
79
- def utf16_index(text, offset)
80
- units = 0
81
- text.each_char.with_index do |char, index|
82
- return index if units >= offset
83
- units += (char.ord > 0xFFFF) ? 2 : 1
84
- end
85
- text.length
86
- end
87
-
88
80
  def to_payload(payload)
89
81
  payload.is_a?(String) ? PlainText.new(payload) : payload
90
82
  end
91
83
 
92
- private_class_method :to_payload, :with_context, :utf16_slice, :utf16_index
84
+ private_class_method :to_payload, :with_context, :utf16_slice
93
85
  end
94
86
  end
95
87
  end
@@ -9,6 +9,7 @@
9
9
  require_relative "extractor"
10
10
  require_relative "segment"
11
11
  require_relative "result"
12
+ require_relative "utf16"
12
13
 
13
14
  module SimpleEnglish
14
15
  module AnnotatedText
@@ -21,10 +22,12 @@ module SimpleEnglish
21
22
  def build(source, spans)
22
23
  segments = []
23
24
  cursor = 0 # byte offset into source
25
+ stream_start = 0 # character offset into the annotation stream
24
26
  emit = lambda do |text:, content:, file_char:, interpret_as: nil|
25
27
  next if content.empty?
26
28
  segments << Segment.new(text: text, content: content, file_char: file_char,
27
- stream_start: segments.sum { |s| s.content.length }, interpret_as: interpret_as)
29
+ stream_start: stream_start, interpret_as: interpret_as)
30
+ stream_start += content.length
28
31
  end
29
32
  spans = spans.sort_by(&:start_byte)
30
33
  spans.each do |span|
@@ -66,14 +69,14 @@ module SimpleEnglish
66
69
 
67
70
  # -> [line, column], both 1-based. Column in UTF-16 code units.
68
71
  def locate(result, utf16_offset)
69
- char = utf16_to_char(result.stream, utf16_offset)
72
+ char = UTF16.index(result.stream, utf16_offset)
70
73
  segment = result.segments.find do |s|
71
74
  char >= s.stream_start && char < s.stream_start + s.content.length
72
75
  end || result.segments.last
73
76
  file_char = segment.file_char + (char - segment.stream_start)
74
77
  starts = line_starts(result.source)
75
78
  line = starts.rindex { |start| start <= file_char } + 1
76
- [line, utf16_column(result.source, starts[line - 1], file_char)]
79
+ [line, UTF16.column(result.source, starts[line - 1], file_char)]
77
80
  end
78
81
 
79
82
  def split(comment)
@@ -96,22 +99,6 @@ module SimpleEnglish
96
99
  starts
97
100
  end
98
101
 
99
- def utf16_to_char(stream, offset)
100
- units = 0
101
- stream.each_char.with_index do |char, index|
102
- return index if units >= offset
103
- units += (char.ord > 0xFFFF) ? 2 : 1
104
- end
105
- stream.length
106
- end
107
-
108
- def utf16_column(source, from, to)
109
- units = 1
110
- source[from...to].each_char { |c| units += (c.ord > 0xFFFF) ? 2 : 1 }
111
- units
112
- end
113
-
114
- private_class_method :split, :char_index, :line_starts,
115
- :utf16_to_char, :utf16_column
102
+ private_class_method :split, :char_index, :line_starts
116
103
  end
117
104
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "paragraph"
4
+ require_relative "utf16"
4
5
 
5
6
  # Markdown stripping and paragraph splitting. Block structure comes
6
7
  # from the tree-sitter Markdown grammar shipped with the pack the
@@ -42,16 +43,12 @@ module SimpleEnglish
42
43
  # Width-preserving replacements keep LanguageTool positions aligned
43
44
  # with the source.
44
45
  line
45
- .gsub(/`[^`]*`/) { |code| "X" * utf16_length(code) }
46
+ .gsub(/`[^`]*`/) { |code| "X" * UTF16.length(code) }
46
47
  .sub(/\A\#{1,6} /) { |marker| " " * marker.length }
47
48
  end
48
49
 
49
50
  def spaces_for(text)
50
- " " * utf16_length(text)
51
- end
52
-
53
- def utf16_length(text)
54
- text.each_char.sum { |char| (char.ord > 0xFFFF) ? 2 : 1 }
51
+ " " * UTF16.length(text)
55
52
  end
56
53
 
57
54
  # A vertical list is not one paragraph: each list item is its own.
@@ -115,7 +112,7 @@ module SimpleEnglish
115
112
  TreeSitterLanguagePack.get_parser("markdown").parse(text).root_node
116
113
  end
117
114
 
118
- private_class_method :strip_line, :spaces_for, :utf16_length, :node_rows,
115
+ private_class_method :strip_line, :spaces_for, :node_rows,
119
116
  :blank_rows, :each_node, :inside_list_item?, :parse
120
117
  end
121
118
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # UTF-16 code-unit arithmetic. LanguageTool is a Java service, and
4
+ # Java strings count UTF-16 code units: an astral-plane character
5
+ # counts as two. Every offset crossing the LT wire goes through
6
+ # here.
7
+
8
+ module SimpleEnglish
9
+ module UTF16
10
+ module_function
11
+
12
+ # The character index in text where the offsetth code unit
13
+ # falls.
14
+ def index(text, offset)
15
+ units = 0
16
+ text.each_char.with_index do |char, index|
17
+ return index if units >= offset
18
+ units += (char.ord > 0xFFFF) ? 2 : 1
19
+ end
20
+ text.length
21
+ end
22
+
23
+ # The code-unit length of text.
24
+ def length(text)
25
+ text.each_char.sum { |char| (char.ord > 0xFFFF) ? 2 : 1 }
26
+ end
27
+
28
+ # The 1-based code-unit column of the character at index to.
29
+ def column(source, from, to)
30
+ length(source[from...to]) + 1
31
+ end
32
+ end
33
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleEnglish
4
- VERSION = "0.10.0"
4
+ VERSION = "0.11.0"
5
5
  end
@@ -8,6 +8,7 @@
8
8
  require_relative "simple_english/version"
9
9
  require_relative "simple_english/lint/finding"
10
10
  require_relative "simple_english/lint/paragraph"
11
+ require_relative "simple_english/lint/utf16"
11
12
  require_relative "simple_english/lint/markdown"
12
13
  require_relative "simple_english/lint/counts"
13
14
  require_relative "simple_english/setup/languagetool"
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/libexec/simple_english/languagetool-server
3
3
  size: 127207544 bytes
4
- sha256: 6a8731f0c1994d32df7a4e1f48578337fa3eb7469c1d16a1c5d07dd040771269
4
+ sha256: 90096407bc281ca375f61588bba5cb60a0906aac6b0ff37e19822a635e212620
@@ -4,7 +4,7 @@
4
4
  "serialNumber" : "urn:uuid:c99881b6-e8ff-383d-92df-6845602c70c5",
5
5
  "version" : 1,
6
6
  "metadata" : {
7
- "timestamp" : "2026-10-15T20:56:12Z",
7
+ "timestamp" : "2026-10-17T21:16:46Z",
8
8
  "lifecycles" : [
9
9
  {
10
10
  "phase" : "build"
@@ -2,13 +2,21 @@
2
2
  <rules lang="en">
3
3
  <category id="SIMPLE_ENGLISH" name="Simple English">
4
4
 
5
+ <!-- LanguageTool splits "you're" into "you" + "'re", so the
6
+ regex matches the apostrophe-initial tokens: "'re", "'ve",
7
+ "'ll", "'d", "'m", and the "n't" token of "don't". The
8
+ apostrophe-s form stays out: it is both the contraction
9
+ "it is" and the possessive, and the tagger does not tell
10
+ them apart reliably. -->
5
11
  <rule id="SE_NO_CONTRACTIONS" name="No contractions">
6
12
  <pattern>
7
- <token regexp="yes">[a-z]+['’](s|t|re|ve|ll|d|m)</token>
13
+ <token regexp="yes">[a-z]*['’](t|re|ve|ll|d|m)</token>
8
14
  </pattern>
9
15
  <message>Write the words in full. No contractions.</message>
10
16
  <example type="incorrect">You <marker>don't</marker> need this file.</example>
17
+ <example type="incorrect">If <marker>you're</marker> connecting, use TCP.</example>
11
18
  <example type="correct">You do not need this file.</example>
19
+ <example type="correct">sqlpipe's IP is in the config.</example>
12
20
  </rule>
13
21
 
14
22
  <rule id="SE_NO_SEMICOLON" name="No semicolons">
@@ -45,6 +53,11 @@
45
53
  <example type="correct">The worker wrote the log.</example>
46
54
  </rule>
47
55
 
56
+ <!-- A passive agent changes the finding, not the rule match:
57
+ "has been read by X" also matches SE_ACTIVE_VOICE, and
58
+ LanguageTool reports only the first of two overlapping
59
+ matches, so this rule stays silent there. The active-voice
60
+ finding names the fix. -->
48
61
  <rule id="SE_PRESENT_PERFECT" name="Simple tenses only">
49
62
  <pattern>
50
63
  <token regexp="yes">have|has|had</token>
@@ -55,11 +68,22 @@
55
68
  <example type="correct">The job completed.</example>
56
69
  </rule>
57
70
 
71
+ <!-- Spirit: a participle clause after a comma leaves the subject
72
+ and the time relation implicit, so the reader must guess. Two
73
+ escapes exist: write a new sentence, or, when the phrase
74
+ states a condition, put the condition first
75
+ (SE_CONDITION_FIRST). No word-list carve-outs: this tool ships
76
+ no approved dictionary, so every comma-plus-ing participle
77
+ fires, including the preposition-like ones. -->
58
78
  <rule id="SE_ING_AFTER_COMMA" name="No -ing after a comma">
59
79
  <pattern><token>,</token><token postag="VBG"><exception scope="next" regexp="yes">[,)]|and|or</exception></token></pattern>
60
- <message>Start a new sentence instead of the -ing phrase.</message>
80
+ <message>Write a new sentence, or put the condition first. A trailing -ing phrase hides who does what and when.</message>
61
81
  <example type="incorrect">The tool runs<marker>, making</marker> it easy.</example>
82
+ <example type="incorrect">Open the valve<marker>, depending</marker> on the pressure.</example>
83
+ <example type="incorrect">Remove the cover<marker>, making</marker> sure not to damage the seal.</example>
62
84
  <example type="correct">The tool runs. It is easy.</example>
85
+ <example type="correct">If the pressure is more than 300 kPa, open the valve.</example>
86
+ <example type="correct">Remove the cover. Make sure that you do not damage the seal.</example>
63
87
  <example type="correct">The walkthrough (accounts, VPC, secrets, troubleshooting) is in the guide.</example>
64
88
  <example type="correct">The guide covers billing, troubleshooting, and support for each environment.</example>
65
89
  <example type="correct">The guide covers billing, troubleshooting and support for each environment.</example>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_english
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - TonyCTHsu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-15 00:00:00.000000000 Z
11
+ date: 2026-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tree_sitter_language_pack
@@ -154,6 +154,7 @@ files:
154
154
  - lib/simple_english/lint/segment.rb
155
155
  - lib/simple_english/lint/span.rb
156
156
  - lib/simple_english/lint/suppressions.rb
157
+ - lib/simple_english/lint/utf16.rb
157
158
  - lib/simple_english/model_context_protocol.rb
158
159
  - lib/simple_english/setup/config.rb
159
160
  - lib/simple_english/setup/fingerprint.rb
@@ -177,7 +178,7 @@ licenses:
177
178
  metadata:
178
179
  homepage_uri: https://github.com/TonyCTHsu/simple-english
179
180
  source_code_uri: https://github.com/TonyCTHsu/simple-english
180
- changelog_uri: https://github.com/TonyCTHsu/simple-english/blob/v0.10.0/CHANGELOG.md
181
+ changelog_uri: https://github.com/TonyCTHsu/simple-english/blob/v0.11.0/CHANGELOG.md
181
182
  post_install_message:
182
183
  rdoc_options: []
183
184
  require_paths: