html-proofer-mailto_awesome 2.0.0 → 2.1.1

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: 9833f8b94e76e14326e0f45a5db0231477a8384e0d84496265d94f412078716d
4
- data.tar.gz: 2ecd2f2141de8b9f56b7a7c85cb11b17ca2f3bc3efb29041217adf019c98c841
3
+ metadata.gz: d3c1456848f4430beff8ea44f6027c6ce37697f546bd18bedf8869343b77957b
4
+ data.tar.gz: 46da1f7c086826914e19521fc66f536b41487d00a04021302d2f07d073a4d423
5
5
  SHA512:
6
- metadata.gz: 33c400bd890f48c071815d5d2dfa14d8892e502c7c72617be6c9525c67dabd4bf13c1a6f66052939ae6eaede31050a726a36a20e84dacac0cb71d8dea7306018
7
- data.tar.gz: 3953271fb34870739b71a4a37976e853c54feb9408a6df6a4355e70d017dd374011e6ce1bd6da9dd2edf9fbca08230f60cae573415d520fbc655f24e09767b3c
6
+ metadata.gz: aabc47a3e8db1c5857e092236022cd5148a932dadfcb5cc1a478037d4d18aef1c5a36a5df88b7e6e200b3ee18300ca71f6857d70ff5944c559fae523efa1ae4f
7
+ data.tar.gz: 9f36a570bc8c78d5b1687d00d1efb8ac554ea6cf8fa914dc5abfd8113e592e29219f747c344c16c41b86a21be8ea9adac4f2b8c4e771251190d7e3677d17c49b
data/.editorconfig ADDED
@@ -0,0 +1,13 @@
1
+ # UTF-8, LF, and spaces. Trailing whitespace is kept so a Markdown hard break (two spaces) stays intact.
2
+ root = true
3
+
4
+ [*]
5
+ charset = utf-8
6
+ end_of_line = lf
7
+ indent_style = space
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = false
10
+ max_line_length = 120
11
+
12
+ [*.md]
13
+ max_line_length = off
@@ -0,0 +1,30 @@
1
+ name: Lint
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+ # Runs on all pull requests targeting any branch
8
+ branches: ["**"]
9
+
10
+ jobs:
11
+ lint:
12
+ name: Prettier & Markdownlint
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - name: Checkout code
17
+ uses: actions/checkout@v7
18
+
19
+ - name: Setup Node.js (tool runtime)
20
+ uses: actions/setup-node@v7
21
+ with:
22
+ node-version: "lts/*" # Floating version is appropriate specifically for Prettier and markdownlint
23
+
24
+ - name: Check formatting (Prettier)
25
+ # Command fails if any files do not meet the formatting rules.
26
+ run: npx prettier@latest --check .
27
+
28
+ - name: Check Markdown (markdownlint)
29
+ # Command fails if any markdown files do not meet the linting rules.
30
+ run: npx markdownlint-cli@latest "**/*.md" --ignore "node_modules"
@@ -0,0 +1,154 @@
1
+ # Release
2
+ #
3
+ # Open or update the release pull request. After that pull request is merged,
4
+ # run the test matrix, tag v1.2.3, push the gem, and open the GitHub Release.
5
+ #
6
+ # Release Please uses the Ruby strategy in release-please-config.json. The
7
+ # manifest .release-please-manifest.json is the last released version. The
8
+ # bootstrap SHA is the 2.1.0 commit, which is already on RubyGems and has no
9
+ # v2.1.0 tag. Commits after that SHA are the next release.
10
+ #
11
+ # skip-github-release keeps the tag off the release pull request. This job
12
+ # creates the tag with rake release, after the tests pass. Bundler tags
13
+ # v1.2.3. Release Please recognizes that shape. A tag shaped like 1.2.3 does
14
+ # not count. The existing tag 2.0.0 is that second shape.
15
+ #
16
+ # RubyGems trusted publishing names this workflow file release.yml and leaves
17
+ # the environment empty. The publish job asks GitHub for an OIDC token
18
+ # (id-token: write). rubygems/release-gem exchanges that token for a
19
+ # short-lived RubyGems credential and runs bundle exec rake release.
20
+ # https://guides.rubygems.org/trusted-publishing/
21
+ #
22
+ # The release pull request is opened with the workflow token. GitHub does not
23
+ # start the test workflow on that pull request. The test job below is the run
24
+ # that has to pass before the gem is pushed.
25
+ #
26
+ # One-time setup
27
+ # 1. On the gem page, Trusted publishers, create a publisher:
28
+ # owner fulldecent, repository html-proofer-mailto_awesome,
29
+ # workflow filename release.yml, environment empty.
30
+ # 2. Repository settings, Actions, General, Workflow permissions: read and
31
+ # write, and allow GitHub Actions to create and approve pull requests.
32
+
33
+ name: Release
34
+
35
+ on:
36
+ push:
37
+ branches: ["main"]
38
+ workflow_dispatch:
39
+ inputs:
40
+ tag:
41
+ description: Tag to publish, for example v1.2.3. Leave empty to open or update the release pull request only.
42
+ required: false
43
+ type: string
44
+
45
+ permissions:
46
+ contents: write
47
+ issues: write
48
+ pull-requests: write
49
+
50
+ jobs:
51
+ propose:
52
+ name: Open or update the release pull request
53
+ if: github.event_name == 'push' || inputs.tag == ''
54
+ runs-on: ubuntu-latest
55
+ outputs:
56
+ pr: ${{ steps.merged.outputs.pr }}
57
+ tag_name: ${{ steps.merged.outputs.tag_name }}
58
+ steps:
59
+ - name: Open the release pull request
60
+ uses: googleapis/release-please-action@v5
61
+ with:
62
+ skip-github-release: true
63
+
64
+ - name: Find a merged release pull request
65
+ id: merged
66
+ if: github.event_name == 'push'
67
+ env:
68
+ GH_TOKEN: ${{ github.token }}
69
+ run: |
70
+ found=$(gh api "repos/$GITHUB_REPOSITORY/commits/$GITHUB_SHA/pulls" --jq '
71
+ .[] | select(.merged_at != null and any(.labels[]; .name == "autorelease: pending"))
72
+ | "\(.number) v\(.title | capture("release (?<v>[0-9]+[.][0-9]+[.][0-9]+)").v)"' | head -n 1)
73
+ if [ -n "$found" ]; then
74
+ read -r pr tag <<< "$found"
75
+ echo "pr=$pr" >> "$GITHUB_OUTPUT"
76
+ echo "tag_name=$tag" >> "$GITHUB_OUTPUT"
77
+ fi
78
+
79
+ test:
80
+ name: Test
81
+ needs: propose
82
+ if: |
83
+ always() &&
84
+ (needs.propose.result == 'success' || needs.propose.result == 'skipped') &&
85
+ (needs.propose.outputs.tag_name != '' ||
86
+ (github.event_name == 'workflow_dispatch' && inputs.tag != ''))
87
+ uses: ./.github/workflows/ruby.yml
88
+
89
+ publish:
90
+ name: Publish gem
91
+ needs: [propose, test]
92
+ if: |
93
+ always() &&
94
+ needs.test.result == 'success' &&
95
+ (needs.propose.outputs.tag_name != '' ||
96
+ (github.event_name == 'workflow_dispatch' && inputs.tag != ''))
97
+ runs-on: ubuntu-latest
98
+ permissions:
99
+ contents: write
100
+ pull-requests: write
101
+ id-token: write
102
+ steps:
103
+ - name: Check out this commit
104
+ uses: actions/checkout@v7
105
+ with:
106
+ persist-credentials: false
107
+
108
+ - name: Set up Ruby
109
+ uses: ruby/setup-ruby@v1
110
+ with:
111
+ ruby-version: "3.4"
112
+ bundler-cache: true
113
+
114
+ - name: Require version.rb to match the tag
115
+ id: tag
116
+ env:
117
+ TAG: ${{ inputs.tag || needs.propose.outputs.tag_name }}
118
+ run: |
119
+ case "$TAG" in
120
+ v*.*.*) ;;
121
+ *) echo "tag must look like v1.2.3" >&2; exit 1 ;;
122
+ esac
123
+ file=$(ruby -e 'load "lib/html/proofer/mailto_awesome/version.rb"; print MailtoAwesome::VERSION')
124
+ version="${TAG#v}"
125
+ if [ "$file" != "$version" ]; then
126
+ echo "version.rb is ${file}; tag version is ${version}" >&2
127
+ exit 1
128
+ fi
129
+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
130
+
131
+ # rake release tags v1.2.3, pushes that tag, and pushes the gem.
132
+ - name: Push the gem
133
+ uses: rubygems/release-gem@v1
134
+
135
+ - name: Publish the GitHub Release
136
+ env:
137
+ GH_TOKEN: ${{ github.token }}
138
+ TAG: ${{ steps.tag.outputs.tag }}
139
+ run: |
140
+ gh release create "$TAG" \
141
+ --repo "$GITHUB_REPOSITORY" \
142
+ --target "$GITHUB_SHA" \
143
+ --title "$TAG" \
144
+ --generate-notes \
145
+ --latest
146
+
147
+ - name: Mark the release pull request tagged
148
+ if: needs.propose.outputs.pr != ''
149
+ env:
150
+ GH_TOKEN: ${{ github.token }}
151
+ PR: ${{ needs.propose.outputs.pr }}
152
+ run: |
153
+ gh api -X DELETE "repos/$GITHUB_REPOSITORY/issues/$PR/labels/autorelease:%20pending"
154
+ gh api "repos/$GITHUB_REPOSITORY/issues/$PR/labels" -f "labels[]=autorelease: tagged"
@@ -1,36 +1,38 @@
1
- # This workflow uses actions that are not certified by GitHub.
2
- # They are provided by a third-party and are governed by
3
- # separate terms of service, privacy policy, and support
4
- # documentation.
5
- # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
- # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
1
+ # Ruby branches still in normal or security maintenance:
2
+ # https://www.ruby-lang.org/en/downloads/branches/
7
3
 
8
- name: Ruby
4
+ name: Test
9
5
 
10
6
  on:
11
7
  push:
12
- branches: [ "main" ]
8
+ branches: ["main"]
13
9
  pull_request:
14
- branches: [ "main" ]
10
+ branches: ["**"]
11
+ workflow_call:
15
12
 
16
13
  permissions:
17
14
  contents: read
18
15
 
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
19
20
  jobs:
20
21
  test:
21
-
22
22
  runs-on: ubuntu-latest
23
23
  strategy:
24
- matrix:
25
- # Only test currently supported Ruby versions: https://www.ruby-lang.org/en/downloads/branches/
26
- ruby-version: ['3.1', '3.2', '3.3']
27
24
  fail-fast: false
25
+ matrix:
26
+ ruby-version: ["3.3", "3.4", "4.0"]
28
27
  steps:
29
- - uses: actions/checkout@v4
30
- - name: Set up Ruby
31
- uses: ruby/setup-ruby@v1
32
- with:
33
- ruby-version: ${{ matrix.ruby-version }}
34
- bundler-cache: true # runs 'bundle install' and caches installed gems automatically
35
- - name: Run tests
36
- run: bundle exec rake
28
+ - name: Checkout code
29
+ uses: actions/checkout@v7
30
+
31
+ - name: Set up Ruby ${{ matrix.ruby-version }}
32
+ uses: ruby/setup-ruby@v1
33
+ with:
34
+ ruby-version: ${{ matrix.ruby-version }}
35
+ bundler-cache: true
36
+
37
+ - name: Run tests
38
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
+ .DS_Store
2
+
1
3
  /.bundle/
2
4
  /.yardoc
3
5
  /_yardoc/
@@ -9,4 +11,10 @@
9
11
 
10
12
  # rspec failure tracking
11
13
  .rspec_status
12
- /vendor/*
14
+ /vendor/*
15
+
16
+ # The lint workflow runs npx, which can leave a local install tree.
17
+ node_modules/
18
+
19
+ # gem build writes the package in the working directory. rake release writes pkg/.
20
+ *.gem
@@ -0,0 +1,3 @@
1
+ {
2
+ "MD013": false
3
+ }
data/.prettierignore ADDED
@@ -0,0 +1 @@
1
+ *.md
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "2.1.1"
3
+ }
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## [2.1.1](https://github.com/fulldecent/html-proofer-mailto_awesome/compare/v2.1.0...v2.1.1) (2026-10-09)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * check a mailto href that has padding around it ([0da97c5](https://github.com/fulldecent/html-proofer-mailto_awesome/commit/0da97c5e3102f01f6a33bf82feb5a006df334f72))
data/Gemfile.lock CHANGED
@@ -1,21 +1,22 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- html-proofer-mailto_awesome (2.0.0)
4
+ html-proofer-mailto_awesome (2.1.1)
5
5
  html-proofer (~> 5.0, >= 5.0.4)
6
+ logger
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
9
10
  specs:
10
11
  Ascii85 (2.0.1)
11
- addressable (2.8.7)
12
- public_suffix (>= 2.0.2, < 7.0)
12
+ addressable (2.9.0)
13
+ public_suffix (>= 2.0.2, < 8.0)
13
14
  afm (0.2.2)
14
15
  async (2.21.2)
15
16
  console (~> 1.29)
16
17
  fiber-annotation
17
18
  io-event (~> 1.6, >= 1.6.5)
18
- base64 (0.3.0)
19
+ benchmark (0.5.0)
19
20
  bigdecimal (3.2.3)
20
21
  console (1.30.2)
21
22
  fiber-annotation
@@ -24,22 +25,23 @@ GEM
24
25
  diff-lcs (1.6.2)
25
26
  ethon (0.15.0)
26
27
  ffi (>= 1.15.0)
27
- ffi (1.17.2-aarch64-linux-gnu)
28
- ffi (1.17.2-aarch64-linux-musl)
29
- ffi (1.17.2-arm-linux-gnu)
30
- ffi (1.17.2-arm-linux-musl)
31
- ffi (1.17.2-arm64-darwin)
32
- ffi (1.17.2-x86_64-darwin)
33
- ffi (1.17.2-x86_64-linux-gnu)
34
- ffi (1.17.2-x86_64-linux-musl)
28
+ ffi (1.17.4-aarch64-linux-gnu)
29
+ ffi (1.17.4-aarch64-linux-musl)
30
+ ffi (1.17.4-arm-linux-gnu)
31
+ ffi (1.17.4-arm-linux-musl)
32
+ ffi (1.17.4-arm64-darwin)
33
+ ffi (1.17.4-x86_64-darwin)
34
+ ffi (1.17.4-x86_64-linux-gnu)
35
+ ffi (1.17.4-x86_64-linux-musl)
35
36
  fiber-annotation (0.2.0)
36
37
  fiber-local (1.1.0)
37
38
  fiber-storage
38
39
  fiber-storage (1.0.1)
39
40
  hashery (2.1.2)
40
- html-proofer (5.0.10)
41
+ html-proofer (5.2.2)
41
42
  addressable (~> 2.3)
42
43
  async (~> 2.1)
44
+ benchmark (~> 0.5)
43
45
  nokogiri (~> 1.13)
44
46
  pdf-reader (~> 2.11)
45
47
  rainbow (~> 3.0)
@@ -47,22 +49,23 @@ GEM
47
49
  yell (~> 2.0)
48
50
  zeitwerk (~> 2.5)
49
51
  io-event (1.11.2)
50
- json (2.14.1)
51
- nokogiri (1.18.10-aarch64-linux-gnu)
52
+ json (2.15.2.1)
53
+ logger (1.7.0)
54
+ nokogiri (1.19.4-aarch64-linux-gnu)
52
55
  racc (~> 1.4)
53
- nokogiri (1.18.10-aarch64-linux-musl)
56
+ nokogiri (1.19.4-aarch64-linux-musl)
54
57
  racc (~> 1.4)
55
- nokogiri (1.18.10-arm-linux-gnu)
58
+ nokogiri (1.19.4-arm-linux-gnu)
56
59
  racc (~> 1.4)
57
- nokogiri (1.18.10-arm-linux-musl)
60
+ nokogiri (1.19.4-arm-linux-musl)
58
61
  racc (~> 1.4)
59
- nokogiri (1.18.10-arm64-darwin)
62
+ nokogiri (1.19.4-arm64-darwin)
60
63
  racc (~> 1.4)
61
- nokogiri (1.18.10-x86_64-darwin)
64
+ nokogiri (1.19.4-x86_64-darwin)
62
65
  racc (~> 1.4)
63
- nokogiri (1.18.10-x86_64-linux-gnu)
66
+ nokogiri (1.19.4-x86_64-linux-gnu)
64
67
  racc (~> 1.4)
65
- nokogiri (1.18.10-x86_64-linux-musl)
68
+ nokogiri (1.19.4-x86_64-linux-musl)
66
69
  racc (~> 1.4)
67
70
  pdf-reader (2.15.0)
68
71
  Ascii85 (>= 1.0, < 3.0, != 2.0.0)
@@ -88,13 +91,10 @@ GEM
88
91
  rspec-support (~> 3.13.0)
89
92
  rspec-support (3.13.6)
90
93
  ruby-rc4 (0.1.5)
91
- timecop (0.9.10)
92
94
  ttfunk (1.8.0)
93
95
  bigdecimal (~> 3.1)
94
96
  typhoeus (1.5.0)
95
97
  ethon (>= 0.9.0, < 0.16.0)
96
- vcr (6.3.1)
97
- base64
98
98
  yell (2.2.2)
99
99
  zeitwerk (2.6.18)
100
100
 
@@ -113,8 +113,6 @@ DEPENDENCIES
113
113
  html-proofer-mailto_awesome!
114
114
  rake (>= 13.0)
115
115
  rspec (~> 3.12)
116
- timecop (~> 0.9)
117
- vcr (~> 6.1)
118
116
 
119
117
  BUNDLED WITH
120
118
  2.6.9
data/README.md CHANGED
@@ -1,80 +1,143 @@
1
- ![Gem](https://img.shields.io/gem/v/html-proofer-mailto_awesome) [![Ruby](https://github.com/fulldecent/html-proofer-mailto_awesome/actions/workflows/ruby.yml/badge.svg)](https://github.com/fulldecent/html-proofer-mailto_awesome/actions/workflows/ruby.yml)
2
-
3
1
  # html-proofer-mailto_awesome
4
- A custom [html-proofer](https://github.com/gjtorikian/html-proofer) test that makes your `mailto:` links awesome.
5
2
 
6
- ## What is an awesome `mailto` link?
3
+ ![Gem](https://img.shields.io/gem/v/html-proofer-mailto_awesome) [![Test](https://github.com/fulldecent/html-proofer-mailto_awesome/actions/workflows/ruby.yml/badge.svg)](https://github.com/fulldecent/html-proofer-mailto_awesome/actions/workflows/ruby.yml) [![Lint](https://github.com/fulldecent/html-proofer-mailto_awesome/actions/workflows/lint.yml/badge.svg)](https://github.com/fulldecent/html-proofer-mailto_awesome/actions/workflows/lint.yml) [![Release](https://github.com/fulldecent/html-proofer-mailto_awesome/actions/workflows/release.yml/badge.svg)](https://github.com/fulldecent/html-proofer-mailto_awesome/actions/workflows/release.yml)
4
+
5
+ An [html-proofer](https://github.com/gjtorikian/html-proofer) check that requires `mailto:` links to carry the header fields you want every message to start with.
6
+
7
+ ## What an awesome mailto link is
7
8
 
8
- We should use awesome links as psychological warfare against users. Users will send us emails with stupid or annoying content that we don't want. At big companies (like Amazon) they have abandoned email altogether because of this reason. So instead we prefill the email with the message we want to receive. It takes active cognitive effort for the user to put in their unwanted message.
9
+ People send email we did not ask for. A bare `mailto:` link opens a blank message, and the sender fills that blank with whatever is on their mind. Prefilling the subject and the body makes the useful message the path of least resistance. Replacing it takes effort.
9
10
 
10
- ❌ For example, this is a not-awesome `mailto` link:
11
+ This is a not-awesome link:
11
12
 
12
13
  ```html
13
14
  <a href="mailto:support@pacificmedicaltraining.com">Email us</a>
14
15
  ```
15
16
 
16
- ✅ This is an awesome link:
17
+ This is an awesome link. The subject and the body are already there:
17
18
 
18
19
  ```html
19
- <a href="mailto:support@pacificmedicaltraining.com?subject=Signing up&amp;body=Hello,\nI'd like to sign up for your course, can you please send me more information.">Email us</a>
20
+ <a
21
+ href="mailto:support@pacificmedicaltraining.com?subject=Signing%20up&amp;body=Hello%2C%0AI%20would%20like%20to%20sign%20up."
22
+ >
23
+ Email us
24
+ </a>
25
+ ```
26
+
27
+ [RFC 6068](https://www.rfc-editor.org/rfc/rfc6068) is the `mailto:` URI scheme. In HTML, write `&amp;` for an ampersand inside the attribute. Header field names are case-insensitive. `Subject` and `subject` are the same field.
28
+
29
+ The same rule is published for HTML-validate as [`nice-checkers/mailto-awesome`](https://github.com/fulldecent/html-validate-nice-checkers#nice-checkersmailto-awesome).
30
+
31
+ ## Installation
32
+
33
+ This gem runs on the Ruby branches that are still in normal or security maintenance: 3.3, 3.4, and 4.0. The list is [Ruby maintenance branches](https://www.ruby-lang.org/en/downloads/branches/). Install one of those Rubies from that page.
34
+
35
+ Add the gem to the application that builds or checks the site:
36
+
37
+ ```ruby
38
+ gem "html-proofer-mailto_awesome"
39
+ ```
40
+
41
+ Then install:
42
+
43
+ ```sh
44
+ bundle install
20
45
  ```
21
46
 
22
- For more reference, see http://marcwitteveen.com/mailtogenerator/
47
+ ## Usage
23
48
 
24
- ## How do I use it
49
+ html-proofer runs only the checks named in `checks`. That option replaces the default list, which is `Links`, `Images`, and `Scripts`. Include those names when you still want them, and add `MailtoAwesome`.
25
50
 
26
- Follow the same instructions as for any [html-proofer custom class](https://github.com/gjtorikian/html-proofer/wiki/Extensions-(custom-classes)).
51
+ Require this gem before `run`. html-proofer discovers the check by looking at classes that are already loaded.
52
+
53
+ ```ruby
54
+ require "html-proofer"
55
+ require "html-proofer-mailto_awesome"
56
+
57
+ desc "Check the built site"
58
+ task :test do
59
+ HTMLProofer.check_directory("_site", {
60
+ checks: ["Links", "Images", "Scripts", "MailtoAwesome"],
61
+ }).run
62
+ end
63
+
64
+ task default: :test
65
+ ```
27
66
 
28
- Our ruby gem is [html-proofer-mailto_awesome](https://rubygems.org/gems/html-proofer-mailto_awesome)
67
+ Run it with Bundler so the gem is on the load path:
29
68
 
30
- 1. Add new dependency to your Ruby project
31
-
32
- In Gemfile:
33
-
34
- gem 'html-proofer-mailto_awesome'
35
-
36
- Or in your .gemspec:
69
+ ```sh
70
+ bundle exec rake
71
+ ```
37
72
 
38
- Gem::Specification.new do |s|
39
- ...
40
- s.add_runtime_dependency 'html-proofer-mailto_awesome'
41
- end
42
-
43
- 2. Create a Rakefile like the following and add it to your project
73
+ `MailtoAwesome` looks at `a` elements. A `mailto:` link passes when every required header field is present. The default required fields are `subject` and `body`. An empty value still counts as present (`subject=`). Text in the address, such as `mailto:subject=trick@example.com`, is not a header field. Spaces and ASCII control characters at either end of the attribute are ignored. [URL parsing](https://url.spec.whatwg.org/#url-parsing) removes those characters before it reads the scheme, so a padded `mailto:support@example.com` is still checked.
44
74
 
45
- task :default => [:test]
46
-
47
- desc 'run Rspec specs'
48
- task :test do
49
- sh 'rspec spec'
50
- end
51
-
52
- 3. Run `bundle install`
75
+ A link that omits a field fails with `mailto: link is missing required parameters: subject, body`. A `mailto:` value that Ruby cannot parse as a URI fails with `mailto: link is malformed and could not be parsed.`
53
76
 
54
- 4. Run `rake`
77
+ `data-proofer-ignore` skips the link, as it does for the other html-proofer checks.
55
78
 
56
- Also if you like, you can enable your project for continuous integration testing with Travis:
79
+ ## Configuration
57
80
 
58
- 1. Set up Travis CI for your project
81
+ `mailto_awesome.required_parameters` replaces the default list. This matches the HTML-validate rule, which uses `requiredParameters` for the same purpose. Pass an empty array when you want the check loaded and no fields required.
59
82
 
60
- 2. Add a `.travis.yml` file like the following to your project and your spec will run automatically
83
+ ```ruby
84
+ HTMLProofer.check_directory("_site", {
85
+ checks: ["Links", "Images", "Scripts", "MailtoAwesome"],
86
+ mailto_awesome: {
87
+ required_parameters: ["subject", "body"],
88
+ },
89
+ }).run
90
+ ```
61
91
 
62
- language: ruby
63
- rvm:
64
- - 2.5.3
65
- For additional tests you can run on your website, see [Lightning Sites](https://github.com/fulldecent/lightning-sites) and for a sample GitHub project that implements this testing and follows many other HTML development best practices, see [HTML Website Template](https://github.com/fulldecent/html-website-template).
92
+ ## Development
66
93
 
67
- For a full example of a website project that includes testing continuous integration testing for awesome mailto links and many other best practices, see our
68
-
69
- ## Contributing
94
+ Clone the repository and install the gems it uses to test itself:
70
95
 
71
- This project is released under the MIT license.
96
+ ```sh
97
+ git clone https://github.com/fulldecent/html-proofer-mailto_awesome.git
98
+ cd html-proofer-mailto_awesome
99
+ bundle install
100
+ bundle exec rake
101
+ ```
72
102
 
73
- Releasing new versions:
103
+ Format the files the lint workflow checks. These commands call `@latest` on purpose. A pinned copy would let your machine rewrite files one way and continuous integration reject them another way. [node.js-template](https://github.com/fulldecent/node.js-template) records that constraint on its `format` script.
74
104
 
75
105
  ```sh
76
- gem bump
77
- rm html-proofer-mailto_awesome-*.gem
78
- gem build html-proofer-mailto_awesome.gemspec
79
- gem push html-proofer-mailto_awesome-*.gem
106
+ npx prettier@latest --write .
107
+ npx markdownlint-cli@latest --fix "**/*.md" --ignore node_modules
80
108
  ```
109
+
110
+ `*.md` is in `.prettierignore`. Prettier does not wrap Markdown. markdownlint does, and [`.markdownlint.json`](.markdownlint.json) turns off the line-length rule.
111
+
112
+ ## Releasing
113
+
114
+ Use `fix:`, `feat:`, or `BREAKING CHANGE:` in commit messages on `main`. A commit whose message starts with `fix:` opens or updates a release pull request that bumps the patch version. `feat:` bumps the minor version. `BREAKING CHANGE:` bumps the major version. One release pull request collects every such commit since the last release. A commit with any other prefix, including `chore:` and `docs:`, does not open that pull request.
115
+
116
+ The [release workflow](.github/workflows/release.yml) uses [release-please](https://github.com/googleapis/release-please) with the Ruby strategy. The configuration is [release-please-config.json](release-please-config.json). [.release-please-manifest.json](.release-please-manifest.json) is the last released version, which is 2.1.0. Merging the release pull request is the release. That pull request sets the version in [lib/html/proofer/mailto_awesome/version.rb](lib/html/proofer/mailto_awesome/version.rb) and in the path spec in [Gemfile.lock](Gemfile.lock), and it writes [CHANGELOG.md](CHANGELOG.md).
117
+
118
+ The publish job then runs the same Ruby matrix as [`.github/workflows/ruby.yml`](.github/workflows/ruby.yml). After those tests pass, it tags `v1.2.3`, pushes that tag, and pushes the gem. The tag is the version Bundler's `rake release` task writes. Release Please reads tags of that shape. The older tag `2.0.0` has no `v`, so it is not a Release Please version. `bootstrap-sha` in the config is commit `b4c37c1`, the commit already published as 2.1.0. The next release is made of commits after that SHA.
119
+
120
+ The release pull request is opened with the workflow token. GitHub does not start [`.github/workflows/ruby.yml`](.github/workflows/ruby.yml) on a pull request opened that way. The publish job's test run is the one that gates the gem.
121
+
122
+ RubyGems.org still requires MFA for this gem (`rubygems_mfa_required`). Publishing from GitHub Actions follows [RubyGems trusted publishing](https://guides.rubygems.org/trusted-publishing/). The gem's trusted publisher names the workflow file `release.yml` and leaves the environment empty. GitHub's OIDC token is exchanged for a short-lived RubyGems credential. No RubyGems API key is stored in this repository.
123
+
124
+ Before the first automated publish, create that trusted publisher. On the gem page, open Trusted publishers and create one with owner `fulldecent`, repository `html-proofer-mailto_awesome`, and workflow filename `release.yml`. Leave the environment empty. In the GitHub repository settings, under Actions, General, Workflow permissions, select read and write permissions and check "Allow GitHub Actions to create and approve pull requests". This repository already has those two settings.
125
+
126
+ ## Maintenance
127
+
128
+ Do this every month or so:
129
+
130
+ 1. Read [Ruby maintenance branches](https://www.ruby-lang.org/en/downloads/branches/). Update `required_ruby_version` and the Ruby matrix in [`.github/workflows/ruby.yml`](.github/workflows/ruby.yml) when a branch leaves security maintenance, or when a new branch enters normal maintenance.
131
+ 1. Review external actions in [`.github/workflows`](.github/workflows). GitHub-supported actions, the ones under the `actions/` organization, need a short review. `ruby/setup-ruby`, `googleapis/release-please-action`, and `rubygems/release-gem` are not in that organization. Read their changelogs before moving the tag.
132
+ 1. Review `html-proofer` against the [5.x releases](https://github.com/gjtorikian/html-proofer/releases). This gem depends on `~> 5.0`, `>= 5.0.4`. It also depends on `logger`, because [Ruby 4.0 removed that library from the default gems](https://stdgems.org/libraries/logger/) and html-proofer still loads it.
133
+ 1. Keep `ffi` at 1.17.4 or newer, and `nokogiri` at 1.19.0 or newer, in `Gemfile.lock`. The x86_64-linux builds of ffi 1.17.2 and nokogiri 1.18.10 set `required_ruby_version` to `< 3.5.dev`, so `bundle install` fails on Ruby 4.0. ffi 1.17.4 and nokogiri 1.19.4 allow Ruby before 4.1. ethon pulls in ffi. html-proofer pulls in nokogiri.
134
+
135
+ ## References
136
+
137
+ 1. We use title case for titles and proper nouns; not for headings and things. This includes our README above as well as our workflow rules and other configuration files. If you have a different policy, then please implement it throughout.
138
+ 1. This project is released under the [MIT license](LICENSE).
139
+ 1. This project is built based on [best practices documented in node.js-template](https://github.com/fulldecent/node.js-template). We took its lint workflow (Prettier and markdownlint, both invoked as `npx @latest`), [`.editorconfig`](.editorconfig), [`.markdownlint.json`](.markdownlint.json), [`.prettierignore`](.prettierignore), and this references section. We did not take its Yarn install or its `.node-version` pin. This is a Ruby gem. The lint job uses Node only as the tool runtime for those two checkers.
140
+ 1. The check follows [`nice-checkers/mailto-awesome`](https://github.com/fulldecent/html-validate-nice-checkers#nice-checkersmailto-awesome) in [@fulldecent/nice-checkers-plugin](https://github.com/fulldecent/html-validate-nice-checkers): default required fields are `subject` and `body`, and the caller can replace that list. Delta: this gem compares header field names case-insensitively because [RFC 6068 section 2](https://www.rfc-editor.org/rfc/rfc6068#section-2) says `<hfname>` is case-insensitive. The HTML-validate rule uses `URLSearchParams`, which compares names case-sensitively.
141
+ 1. html-proofer custom checks are loaded by class name and selected with the `checks` option. Passing `checks` replaces the default list. That behavior is documented in the [html-proofer README](https://github.com/gjtorikian/html-proofer#custom-tests).
142
+ 1. Ruby versions in the gemspec and in continuous integration are the branches still in normal or security maintenance, from [Ruby maintenance branches](https://www.ruby-lang.org/en/downloads/branches/). Ruby 4.0 does not ship `logger` as a default gem. This gem depends on the [`logger` gem](https://stdgems.org/libraries/logger/) so html-proofer can load on that Ruby.
143
+ 1. Releases follow [release-please](https://github.com/googleapis/release-please) in manifest mode, with the [Ruby strategy](https://github.com/googleapis/release-please/blob/main/docs/customizing.md). Commit messages follow [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/). The release pull request is the review gate. [semantic-release](https://github.com/semantic-release/semantic-release) commits onto the default branch and assumes Node. Publishing the gem follows [RubyGems trusted publishing](https://guides.rubygems.org/trusted-publishing/) and [`rubygems/release-gem`](https://github.com/rubygems/release-gem). The trusted publisher names `release.yml` and leaves the environment empty. `rake release` creates the `v1.2.3` tag after the tests pass, because a tag created earlier would exist while the tests can still fail. A tag created by `GITHUB_TOKEN` does not start another workflow ([GitHub docs](https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow)), so the publish job is in this same workflow. The shape of the workflow follows [php-template](https://github.com/fulldecent/php-template)'s release workflow: Release Please opens the pull request, and the publish job creates the tag. Delta: this job pushes a gem with trusted publishing, and the version lives in `version.rb` because the Ruby strategy updates that file. php-template takes the version from the tag alone.
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
- require "html/proofer/mailto_awesome"
4
+ require "html-proofer-mailto_awesome"
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -21,8 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- # Minimum Ruby version supported by the Ruby project: https://www.ruby-lang.org/en/downloads/branches/
25
- spec.required_ruby_version = ">= 3.1.0"
24
+ # Ruby branches that are still in normal or security maintenance:
25
+ # https://www.ruby-lang.org/en/downloads/branches/
26
+ spec.required_ruby_version = ">= 3.3.0"
26
27
 
27
28
  spec.metadata = {
28
29
  "bug_tracker_uri" => "https://github.com/fulldecent/html-proofer-mailto_awesome/issues",
@@ -31,10 +32,11 @@ Gem::Specification.new do |spec|
31
32
  "rubygems_mfa_required" => "true"
32
33
  }
33
34
 
35
+ spec.add_dependency "html-proofer", "~> 5.0", ">= 5.0.4"
36
+ # Ruby 4.0 removed logger from the default gems. html-proofer still loads it.
37
+ # https://stdgems.org/libraries/logger/
38
+ spec.add_dependency "logger"
34
39
  spec.add_development_dependency "bundler", ">= 2.0"
35
40
  spec.add_development_dependency "rake", ">= 13.0"
36
- spec.add_runtime_dependency 'html-proofer', '~> 5.0', '>= 5.0.4'
37
- spec.add_development_dependency 'rspec', '~> 3.12'
38
- spec.add_development_dependency 'vcr', '~> 6.1'
39
- spec.add_development_dependency 'timecop', '~> 0.9'
41
+ spec.add_development_dependency "rspec", "~> 3.12"
40
42
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MailtoAwesome
4
- VERSION = "2.0.0"
5
- end
4
+ VERSION = "2.1.1"
5
+ end
@@ -1,10 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "html/proofer/mailto_awesome/version"
4
3
  require_relative "mailto_awesome"
5
-
6
- module HTMLProofer
7
- module MailtoAwesome
8
- class Error < StandardError; end
9
- end
10
- end
@@ -1,31 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "html/proofer/mailto_awesome/version"
4
+ # Ruby 4.0 removed logger from the default gems. html-proofer still loads it.
5
+ # https://stdgems.org/libraries/logger/
6
+ require "logger"
7
+ require "html-proofer"
8
+ require "uri"
4
9
 
5
10
  module HTMLProofer
6
11
  class Check
12
+ # Reports mailto links that omit the header fields a recipient asked for.
13
+ # Header field names follow RFC 6068: hfname is case-insensitive.
14
+ # https://www.rfc-editor.org/rfc/rfc6068#section-2
7
15
  class MailtoAwesome < HTMLProofer::Check
8
- def mailto?
9
- return false if @link.ignore? || @link.href.nil?
10
- @link.href.match(/^mailto:/i)
11
- end
12
-
13
- def awesome?
14
- @link.href.downcase.include?('subject=') && @link.href.downcase.include?('body=')
15
- end
16
-
16
+ DEFAULT_REQUIRED_PARAMETERS = ["subject", "body"].freeze
17
+
18
+ # WHATWG URL parsing removes leading and trailing C0 controls and spaces
19
+ # before it reads the scheme. " mailto:support@example.com" is a mailto link.
20
+ # https://url.spec.whatwg.org/#url-parsing
21
+ LEADING_OR_TRAILING_URL_SPACE = /\A[\x00-\x1F ]+|[\x00-\x1F ]+\z/
22
+
17
23
  def run
18
- # Check if the mailto awesome check is enabled via runner options
19
- return unless @runner && @runner.instance_variable_get('@options')&.fetch(:check_mailto_awesome, false)
20
-
21
- @html.css('a').each do |node|
24
+ @html.css("a").each do |node|
22
25
  @link = create_element(node)
23
-
24
- if mailto? && !awesome?
25
- add_failure("This is a not-awesome mailto link!", element: @link)
26
+ next if @link.ignore?
27
+
28
+ href = node["href"]
29
+ next unless href.is_a?(String)
30
+
31
+ href = href.gsub(LEADING_OR_TRAILING_URL_SPACE, "")
32
+ next unless href.match?(/\Amailto:/i)
33
+
34
+ begin
35
+ names = header_names(href)
36
+ rescue URI::InvalidURIError
37
+ add_failure("mailto: link is malformed and could not be parsed.", element: @link)
38
+ next
26
39
  end
40
+
41
+ missing = required_parameters.reject { |name| names.include?(name) }
42
+ next if missing.empty?
43
+
44
+ add_failure("mailto: link is missing required parameters: #{missing.join(", ")}", element: @link)
27
45
  end
28
46
  end
47
+
48
+ private
49
+
50
+ def required_parameters
51
+ configured = @runner.options[:mailto_awesome]
52
+ names = configured[:required_parameters] || configured["required_parameters"] if configured.is_a?(Hash)
53
+ names = DEFAULT_REQUIRED_PARAMETERS if names.nil?
54
+ Array(names).map { |name| name.to_s.downcase }
55
+ end
56
+
57
+ def header_names(href)
58
+ # Nokogiri has already decoded &amp;. A caller that passes the source
59
+ # text still has the entity, which RFC 6068 requires in HTML.
60
+ semantic = href.gsub("&amp;", "&").gsub("&lt;", "<").gsub("&gt;", ">")
61
+ uri = URI.parse(semantic)
62
+ raise URI::InvalidURIError, semantic unless uri.is_a?(URI::MailTo)
63
+
64
+ Array(uri.headers).map { |name, _value| name.to_s.downcase }
65
+ end
29
66
  end
30
67
  end
31
68
  end
@@ -0,0 +1,11 @@
1
+ {
2
+ "bootstrap-sha": "b4c37c17fee1ec30cb127daad3f5c437f1c341db",
3
+ "packages": {
4
+ ".": {
5
+ "release-type": "ruby",
6
+ "package-name": "html-proofer-mailto_awesome",
7
+ "include-component-in-tag": false,
8
+ "version-file": "lib/html/proofer/mailto_awesome/version.rb"
9
+ }
10
+ }
11
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-proofer-mailto_awesome
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Entriken
@@ -10,105 +10,98 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: bundler
13
+ name: html-proofer
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: '2.0'
19
- type: :development
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
16
+ - - "~>"
24
17
  - !ruby/object:Gem::Version
25
- version: '2.0'
26
- - !ruby/object:Gem::Dependency
27
- name: rake
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
18
+ version: '5.0'
30
19
  - - ">="
31
20
  - !ruby/object:Gem::Version
32
- version: '13.0'
33
- type: :development
21
+ version: 5.0.4
22
+ type: :runtime
34
23
  prerelease: false
35
24
  version_requirements: !ruby/object:Gem::Requirement
36
25
  requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '5.0'
37
29
  - - ">="
38
30
  - !ruby/object:Gem::Version
39
- version: '13.0'
31
+ version: 5.0.4
40
32
  - !ruby/object:Gem::Dependency
41
- name: html-proofer
33
+ name: logger
42
34
  requirement: !ruby/object:Gem::Requirement
43
35
  requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '5.0'
47
36
  - - ">="
48
37
  - !ruby/object:Gem::Version
49
- version: 5.0.4
38
+ version: '0'
50
39
  type: :runtime
51
40
  prerelease: false
52
41
  version_requirements: !ruby/object:Gem::Requirement
53
42
  requirements:
54
- - - "~>"
55
- - !ruby/object:Gem::Version
56
- version: '5.0'
57
43
  - - ">="
58
44
  - !ruby/object:Gem::Version
59
- version: 5.0.4
45
+ version: '0'
60
46
  - !ruby/object:Gem::Dependency
61
- name: rspec
47
+ name: bundler
62
48
  requirement: !ruby/object:Gem::Requirement
63
49
  requirements:
64
- - - "~>"
50
+ - - ">="
65
51
  - !ruby/object:Gem::Version
66
- version: '3.12'
52
+ version: '2.0'
67
53
  type: :development
68
54
  prerelease: false
69
55
  version_requirements: !ruby/object:Gem::Requirement
70
56
  requirements:
71
- - - "~>"
57
+ - - ">="
72
58
  - !ruby/object:Gem::Version
73
- version: '3.12'
59
+ version: '2.0'
74
60
  - !ruby/object:Gem::Dependency
75
- name: vcr
61
+ name: rake
76
62
  requirement: !ruby/object:Gem::Requirement
77
63
  requirements:
78
- - - "~>"
64
+ - - ">="
79
65
  - !ruby/object:Gem::Version
80
- version: '6.1'
66
+ version: '13.0'
81
67
  type: :development
82
68
  prerelease: false
83
69
  version_requirements: !ruby/object:Gem::Requirement
84
70
  requirements:
85
- - - "~>"
71
+ - - ">="
86
72
  - !ruby/object:Gem::Version
87
- version: '6.1'
73
+ version: '13.0'
88
74
  - !ruby/object:Gem::Dependency
89
- name: timecop
75
+ name: rspec
90
76
  requirement: !ruby/object:Gem::Requirement
91
77
  requirements:
92
78
  - - "~>"
93
79
  - !ruby/object:Gem::Version
94
- version: '0.9'
80
+ version: '3.12'
95
81
  type: :development
96
82
  prerelease: false
97
83
  version_requirements: !ruby/object:Gem::Requirement
98
84
  requirements:
99
85
  - - "~>"
100
86
  - !ruby/object:Gem::Version
101
- version: '0.9'
87
+ version: '3.12'
102
88
  description: A custom html-proofer test that makes your mailto links awesome
103
89
  email: github.com@phor.net
104
90
  executables: []
105
91
  extensions: []
106
92
  extra_rdoc_files: []
107
93
  files:
94
+ - ".editorconfig"
108
95
  - ".github/FUNDING.yml"
96
+ - ".github/workflows/lint.yml"
97
+ - ".github/workflows/release.yml"
109
98
  - ".github/workflows/ruby.yml"
110
99
  - ".gitignore"
100
+ - ".markdownlint.json"
101
+ - ".prettierignore"
102
+ - ".release-please-manifest.json"
111
103
  - ".rspec"
104
+ - CHANGELOG.md
112
105
  - Gemfile
113
106
  - Gemfile.lock
114
107
  - LICENSE
@@ -120,6 +113,7 @@ files:
120
113
  - lib/html-proofer-mailto_awesome.rb
121
114
  - lib/html/proofer/mailto_awesome/version.rb
122
115
  - lib/mailto_awesome.rb
116
+ - release-please-config.json
123
117
  homepage: https://github.com/fulldecent/html-proofer-mailto_awesome
124
118
  licenses:
125
119
  - MIT
@@ -135,7 +129,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
135
129
  requirements:
136
130
  - - ">="
137
131
  - !ruby/object:Gem::Version
138
- version: 3.1.0
132
+ version: 3.3.0
139
133
  required_rubygems_version: !ruby/object:Gem::Requirement
140
134
  requirements:
141
135
  - - ">="