jscontact 0.1.0 → 0.2.0

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: 2b5fd75452d4b1982b14996be3513fef5543d65f36e026b75ab0fb320a7d5f16
4
- data.tar.gz: 0f938551f087628168cb7a5fe896acf1f339fb5034355305da5c2175b6deada2
3
+ metadata.gz: 5d92a19bb9e19ed8bc57c8b3382cb2364f80e992109fc4f9bebc2abc1ec2729e
4
+ data.tar.gz: 83aea8cf6c39aa19696ca6b6085cf236f5f91c52efc59d829579abbef5c358d3
5
5
  SHA512:
6
- metadata.gz: 053177fa21d75e63a1a4434ba7418aef8096d0a3399a315bd80bc393c05f79ed6509a77202be8197f773172079580fc0e75b75738af1c5f6e57285c5702afaa9
7
- data.tar.gz: bd31c7364dca93a41ceb9dd11585b89e584df900d1e722598b5b43b65eec08d23f0324d43bc9eb1cbac5ecf99e3b963b48acec9b7ff10e0bdf3ef105a05e8440
6
+ metadata.gz: 5c472a9ef316602575a4a82ca62410a1ffd4d782145ad0a29f86d6f7a647e0f7ddc71d86219c5877c8741220102210fe022480c3d3ee6f41c6bd37e858c87909
7
+ data.tar.gz: 18c076269b700e84346537cd6202c1c376920ba6bcec29ba673b4256b18b27be470975abe26451a68ca54a3c5898459e7879fdc1c708a6af57977f303ecce877
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 - 2026-10-12
4
+
5
+ - Preserve leap seconds when converting vCard timestamps to UTC.
6
+ - Retain timestamps without a UTC offset in vCard metadata instead of interpreting them in the system time zone.
7
+
3
8
  ## 0.1.0 - 2026-10-12
4
9
 
5
10
  Initial release.
data/README.md CHANGED
@@ -1,12 +1,33 @@
1
- # JSContact
1
+ <h1 align="center">JSContact</h1>
2
2
 
3
- [![Ruby](https://github.com/ydah/jscontact/actions/workflows/main.yml/badge.svg)](https://github.com/ydah/jscontact/actions/workflows/main.yml)
3
+ <p align="center">JSON contact cards with validation and vCard conversion.</p>
4
+
5
+ <p align="center">
6
+ <a href="https://rubygems.org/gems/jscontact"><img src="https://img.shields.io/gem/v/jscontact" alt="Gem version"></a>
7
+ <a href="https://github.com/ydah/jscontact/actions/workflows/main.yml"><img src="https://github.com/ydah/jscontact/actions/workflows/main.yml/badge.svg?branch=main" alt="CI"></a>
8
+ <a href="https://www.ruby-lang.org/"><img src="https://img.shields.io/badge/Ruby-%3E%3D%203.3-CC342D?logo=ruby&amp;logoColor=white" alt="Ruby 3.3 or later"></a>
9
+ <a href="LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License"></a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ <a href="#installation">Installation</a> &middot;
14
+ <a href="#quick-start">Quick start</a> &middot;
15
+ <a href="#supported-scope">Supported scope</a> &middot;
16
+ <a href="#development">Development</a> &middot;
17
+ <a href="#license">License</a>
18
+ </p>
4
19
 
5
20
  Parse, validate, build, and convert JSContact contact cards in Ruby. Supports
6
21
  [RFC 9553](https://www.rfc-editor.org/rfc/rfc9553),
7
22
  [RFC 9555](https://www.rfc-editor.org/rfc/rfc9555), and
8
23
  [RFC 9982](https://www.rfc-editor.org/rfc/rfc9982).
9
24
 
25
+ ## Features
26
+
27
+ - Build typed JSContact 2.0 cards and read existing 1.0 cards.
28
+ - Apply patches and localizations while preserving vendor extensions.
29
+ - Convert vCard 4.0 through an optional jcard_jcal integration.
30
+
10
31
  Unknown properties, vendor extensions, and map identifiers survive JSON round
11
32
  trips. New cards use JSContact 2.0; reading a 1.0 card keeps its version until you
12
33
  explicitly upgrade it.
@@ -15,16 +36,20 @@ explicitly upgrade it.
15
36
 
16
37
  Requires Ruby 3.3 or later. CI also tests JRuby and TruffleRuby on Linux and macOS.
17
38
 
39
+ Add the gem to your Gemfile:
40
+
18
41
  ```ruby
19
42
  gem "jscontact"
20
43
  # Add only when using the optional vCard converter:
21
44
  gem "jcard_jcal", "~> 0.1.0"
22
45
  ```
23
46
 
47
+ Then run `bundle install`.
48
+
24
49
  The JSON API depends on `json` and `tzinfo`. On systems without a zoneinfo database
25
50
  (such as Windows), also install `tzinfo-data` for time zone and country validation.
26
51
 
27
- ## Read and build cards
52
+ ## Quick start
28
53
 
29
54
  ```ruby
30
55
  require "jscontact"
@@ -124,6 +149,8 @@ vCard 4.0. A missing UID stays absent when converting to JSContact 2.0. Requesti
124
149
  Conversion preserves data, rather than the original text's property order,
125
150
  folding, or choice of equivalent representation. Date forms without a JSContact
126
151
  equivalent and unmatched birth/death place properties are retained in `vCardProps`.
152
+ Timestamp conversion preserves leap seconds. Timestamps without a UTC offset
153
+ remain in `vCardProps` or `vCardParams`, since no UTC instant can be inferred.
127
154
 
128
155
  JSContact date fields use the Gregorian calendar even when `calendarScale` names
129
156
  another calendar. The converter preserves non-Gregorian vCard CALSCALE properties
@@ -177,9 +204,9 @@ vulnerabilities.
177
204
  bundle install
178
205
  bundle exec rake # fetch and verify external RFC inputs, then test
179
206
  COVERAGE=1 bundle exec rake # minimum 90% line coverage
180
- bundle exec rubocop
181
207
  bundle exec rbs -I sig validate
182
- bundle exec ruby script/interop.rb # requires stable Rust; pinned calcard comparison
208
+ bundle exec ruby script/check_syntax.rb
209
+ bundle exec ruby script/check_licenses.rb
183
210
  bundle exec ruby script/benchmark.rb # time, allocation and RSS measurements at limits
184
211
  bundle exec ruby script/update_registry.rb # verify pinned IANA registry coverage
185
212
  bundle exec ruby script/update_registry.rb --refresh # audit current IANA data and update pins
@@ -188,10 +215,10 @@ bundle exec ruby script/update_registry.rb --refresh # audit current IANA data a
188
215
  The suite checks 97 generated RFC examples, both directions of 54 vCard conversion
189
216
  pairs, malformed input, patches, limits, and deterministic random round trips.
190
217
  See [conformance notes](docs/conformance.md) for extraction corrections, reported
191
- errata, and the two precisely checked upstream interoperability differences.
218
+ errata, and the current comparison scope.
192
219
  The [boundary measurements](docs/performance.md) explain the default limits.
193
220
 
194
- RFC originals, extracted examples, IANA downloads, and external comparison sources
221
+ RFC originals, extracted examples, and IANA downloads
195
222
  live only in ignored `tmp/` directories. Downloads retain their applicable notices;
196
223
  RFC source hashes and the generated corpus fingerprint are checked before testing.
197
224
  The packaged gem contains library code, original schema metadata, RBS, and user
@@ -205,8 +232,14 @@ the gem version and CHANGELOG, then push the matching `vVERSION` tag. The workfl
205
232
  tests, builds, publishes through OIDC, and creates a GitHub release from that
206
233
  version's CHANGELOG entry. A version already on RubyGems is not published again.
207
234
 
235
+ ## Contributing
236
+
237
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/ydah/jscontact/issues). See [Development](#development) for the checks to run before submitting a change. Report security vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
238
+
208
239
  ## License
209
240
 
210
- The Ruby library is available under the [MIT License](LICENSE.txt). External test
211
- inputs and comparison dependencies retain their own licenses and are not included
212
- in the gem.
241
+ The Ruby library is available under the [MIT License](LICENSE.txt). Added runtime
242
+ and development libraries must offer MIT terms, including transitive dependencies;
243
+ Ruby runtimes, standard libraries, and bundled tools are explicit exceptions.
244
+ External RFC and registry test inputs retain their notices and are not included
245
+ in the gem. See [provenance and dependency review](docs/provenance.md).
data/SECURITY.md CHANGED
@@ -4,3 +4,10 @@ Report vulnerabilities through [GitHub private vulnerability reporting](https://
4
4
  Please include a minimal reproducer and the affected gem and Ruby versions.
5
5
 
6
6
  The library treats documents as data. It does not retrieve contact URIs or execute embedded content.
7
+
8
+ Dependency policy: added runtime and development libraries, including transitive
9
+ dependencies, must offer MIT terms. Ruby runtimes, standard libraries, and bundled
10
+ tools are explicit exceptions. Externally downloaded RFC/registry test data retain
11
+ their own notices and stay outside the repository and gem package. Dependency
12
+ license review does not constitute a cryptographic or application security audit.
13
+ See [provenance and dependency review](docs/provenance.md) for the review scope.
@@ -130,6 +130,8 @@ module Jscontact
130
130
 
131
131
  key = SCALARS.fetch(name)
132
132
  converted = %w[created rev].include?(name) ? timestamp(value) : value
133
+ return preserve(prop) if converted.nil?
134
+
133
135
  converted = converted.downcase if name == "kind"
134
136
  converted = normalize_language(converted) if name == "language"
135
137
  @card[key] = converted
@@ -215,10 +217,13 @@ module Jscontact
215
217
  consumed << parameter
216
218
  end
217
219
  when "note"
218
- object["created"] = timestamp(params["created"], compact: true) if params["created"]
220
+ if params["created"] && (created = timestamp(params["created"], compact: true))
221
+ object["created"] = created
222
+ consumed << "created"
223
+ end
219
224
  author = { "name" => params["author-name"], "uri" => params["author"] }.compact
220
225
  object["author"] = author unless author.empty?
221
- consumed += %w[created author author-name]
226
+ consumed += %w[author author-name]
222
227
  when "expertise", "hobby", "interest"
223
228
  if params["level"]
224
229
  level = params["level"].downcase
@@ -395,7 +400,11 @@ module Jscontact
395
400
 
396
401
  def timestamp(value, compact: false)
397
402
  value = JCardJCal::ValueTypes.from_text(value, "timestamp", format: :vcard) if compact
398
- Time.iso8601(value).utc.iso8601
403
+ return unless value.match?(/(?:Z|[+-]\d{2}(?::\d{2})?)\z/)
404
+
405
+ # Convert the minute separately because Ruby Time normalizes leap seconds.
406
+ minute = Time.iso8601("#{value[0, 17]}00#{value[19..]}").utc
407
+ "#{minute.strftime("%Y-%m-%dT%H:%M:")}#{value[17, 2]}Z"
399
408
  rescue ArgumentError
400
409
  raise ConversionError, "invalid vCard timestamp"
401
410
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jscontact
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jscontact
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada
@@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  requirements: []
101
- rubygems_version: 4.0.16
101
+ rubygems_version: 3.6.9
102
102
  specification_version: 4
103
103
  summary: Read, validate, and convert JSContact contact cards
104
104
  test_files: []