jq 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 85a8def8b4728ce33cb6bf3322969e08d95abd40dec1efd317a7a0de764f333a
4
+ data.tar.gz: 96a55036c41973603dba2bbcea2970ebd6312fa2334c1afb79feba3327015228
5
+ SHA512:
6
+ metadata.gz: 301b55c4c77ec72aca48de6cf73d8ef421710b0cea7c6aa041191c0d39cbbe1763530920bdcf98c333d80c07ce4677c5fad78f3841ec8448e7ce2db3571a9148
7
+ data.tar.gz: 6d3c8b437eff186dc30e24f6add659312c37c4f0c4f73c602f172d93655c2eb02362ed128d21dd59f6b47bbb2f14805c1214b20ef71348eae92d4710aebd7b6d
@@ -0,0 +1,32 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ workflow_call:
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, macos-latest]
16
+ ruby: ['3.3', '3.4']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Install autotools (macOS)
22
+ if: runner.os == 'macOS'
23
+ run: brew install autoconf automake libtool
24
+
25
+ - name: Set up Ruby
26
+ uses: ruby/setup-ruby@v1
27
+ with:
28
+ ruby-version: ${{ matrix.ruby }}
29
+ bundler-cache: true
30
+
31
+ - name: Run tests
32
+ run: bundle exec rake
@@ -0,0 +1,38 @@
1
+ name: Release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: write
8
+ id-token: write
9
+
10
+ jobs:
11
+ ci:
12
+ uses: ./.github/workflows/ci.yml
13
+
14
+ release:
15
+ runs-on: ubuntu-latest
16
+ environment: Release
17
+
18
+ needs: [ci]
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Set up Ruby
24
+ uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: '3.3'
27
+ bundler-cache: true
28
+
29
+ - name: Publish to RubyGems
30
+ uses: rubygems/release-gem@v1
31
+ with:
32
+ await-release: true
33
+
34
+ - name: Create GitHub Release
35
+ uses: softprops/action-gh-release@v2
36
+ with:
37
+ files: pkg/*.gem
38
+ generate_release_notes: true
data/.gitignore ADDED
@@ -0,0 +1,49 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ spec/examples.txt
12
+
13
+ # Compiled extensions
14
+ *.bundle
15
+ *.so
16
+ *.o
17
+ *.a
18
+ *.log
19
+
20
+ # Compiled extension outputs
21
+ /lib/jq/jq_ext.bundle
22
+ /lib/jq/jq_ext.so
23
+ /lib/jq/jq_ext.dll
24
+
25
+ # Build artifacts
26
+ /ext/jq/*.o
27
+ /ext/jq/*.so
28
+ /ext/jq/*.bundle
29
+ /ext/jq/Makefile
30
+ /ext/jq/mkmf.log
31
+ /ext/jq/tmp/
32
+
33
+ # miniportile
34
+ /ext/jq/ports/
35
+ /ext/jq/tmp/
36
+
37
+ # OS files
38
+ .DS_Store
39
+ Thumbs.db
40
+
41
+ # Editor files
42
+ *.swp
43
+ *.swo
44
+ *~
45
+ .vscode/
46
+ .idea/
47
+
48
+ # Gem files
49
+ *.gem
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.3.9
data/CHANGELOG.md ADDED
@@ -0,0 +1,49 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2026-01-26
9
+
10
+ ### Added
11
+
12
+ - Initial release of jq-ruby gem
13
+ - `JQ.filter` method for applying jq filters to JSON
14
+ - Support for `raw_output` option (jq -r)
15
+ - Support for `compact_output` option (jq -c)
16
+ - Support for `sort_keys` option (jq -S)
17
+ - Support for `multiple_outputs` option to return all results
18
+ - `JQ.validate_filter!` method for validating jq filter expressions
19
+ - Exception hierarchy:
20
+ - `JQ::Error` - Base exception class
21
+ - `JQ::CompileError` - Invalid jq filter
22
+ - `JQ::RuntimeError` - Runtime execution error
23
+ - `JQ::ParseError` - Invalid JSON input
24
+ - Bundled jq 1.8.1 compiled from source via mini_portile2
25
+ - Self-contained installation with no system dependencies
26
+ - SHA256 verification of jq source tarball
27
+ - Static compilation for reliability
28
+ - Comprehensive test suite with >95% coverage
29
+ - Core functionality tests
30
+ - Filter validation tests
31
+ - Error handling tests
32
+ - Security tests
33
+ - Memory leak detection tests
34
+ - Complete documentation
35
+ - README with usage examples
36
+ - SECURITY.md with security considerations
37
+ - RBS type signatures
38
+ - Ruby 3.3+ required
39
+ - Thread safety documentation (jq is NOT thread-safe)
40
+
41
+ ### Security
42
+
43
+ - Proper jv memory lifecycle management prevents buffer overflows
44
+ - All inputs validated for type before processing
45
+ - JSON parsed by jq's built-in parser (no eval/injection risk)
46
+ - Filter expressions cannot execute system commands (safe by design)
47
+ - Tested with large inputs, deeply nested structures, and malicious filters
48
+
49
+ [1.0.0]: https://github.com/persona-id/jq-ruby/releases/tag/v1.0.0
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ jq (1.0.0)
5
+ mini_portile2 (~> 2.8)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.6.2)
11
+ mini_portile2 (2.8.9)
12
+ rake (13.3.1)
13
+ rake-compiler (1.3.1)
14
+ rake
15
+ rspec (3.13.2)
16
+ rspec-core (~> 3.13.0)
17
+ rspec-expectations (~> 3.13.0)
18
+ rspec-mocks (~> 3.13.0)
19
+ rspec-core (3.13.6)
20
+ rspec-support (~> 3.13.0)
21
+ rspec-expectations (3.13.5)
22
+ diff-lcs (>= 1.2.0, < 2.0)
23
+ rspec-support (~> 3.13.0)
24
+ rspec-mocks (3.13.7)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.13.0)
27
+ rspec-support (3.13.6)
28
+
29
+ PLATFORMS
30
+ arm64-darwin-24
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ jq!
35
+ rake (~> 13.0)
36
+ rake-compiler (~> 1.2)
37
+ rspec (~> 3.13)
38
+
39
+ BUNDLED WITH
40
+ 2.7.2
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Persona Identity Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,214 @@
1
+ # jq-ruby
2
+
3
+ A minimal, security-focused Ruby gem that wraps the jq C library for JSON transformation.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'jq'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install it yourself:
20
+
21
+ ```bash
22
+ gem install jq
23
+ ```
24
+
25
+ **Note:** This gem bundles jq 1.8.1 and builds it from source automatically during installation. No system dependencies are required.
26
+
27
+ ## Usage
28
+
29
+ ### Basic Filtering
30
+
31
+ ```ruby
32
+ require 'jq'
33
+
34
+ # Basic filter
35
+ result = JQ.filter('{"name":"Alice","age":30}', '.name')
36
+ # => "\"Alice\""
37
+
38
+ # Identity filter (compact output is the default)
39
+ result = JQ.filter('{"a":1}', '.')
40
+ # => "{\"a\":1}"
41
+
42
+ # Nested access
43
+ result = JQ.filter('{"user":{"name":"Bob"}}', '.user.name')
44
+ # => "\"Bob\""
45
+
46
+ # Array operations
47
+ result = JQ.filter('[1,2,3]', '.[1]')
48
+ # => "2"
49
+ ```
50
+
51
+ ### Options
52
+
53
+ #### Raw Output
54
+
55
+ Get raw strings without JSON encoding (equivalent to `jq -r`):
56
+
57
+ ```ruby
58
+ result = JQ.filter('{"name":"Alice"}', '.name', raw_output: true)
59
+ # => "Alice" (not "\"Alice\"")
60
+ ```
61
+
62
+ #### Compact Output
63
+
64
+ **Compact output is the default.** JSON is returned on a single line without extra whitespace:
65
+
66
+ ```ruby
67
+ result = JQ.filter('{"a":1,"b":2}', '.')
68
+ # => "{\"a\":1,\"b\":2}" (default)
69
+
70
+ # To get pretty-printed output, set compact_output: false
71
+ result = JQ.filter('{"a":1,"b":2}', '.', compact_output: false)
72
+ # => "{\n \"a\": 1,\n \"b\": 2\n}"
73
+ ```
74
+
75
+ #### Sort Keys
76
+
77
+ Sort object keys for deterministic output (equivalent to `jq -S`):
78
+
79
+ ```ruby
80
+ result = JQ.filter('{"z":1,"a":2}', '.', sort_keys: true)
81
+ # => "{\"a\":2,\"z\":1}"
82
+ ```
83
+
84
+ #### Multiple Outputs
85
+
86
+ Return an array of all results instead of just the first:
87
+
88
+ ```ruby
89
+ result = JQ.filter('[1,2,3]', '.[]', multiple_outputs: true)
90
+ # => ["1", "2", "3"]
91
+
92
+ # Combining with raw_output
93
+ result = JQ.filter('["a","b","c"]', '.[]', multiple_outputs: true, raw_output: true)
94
+ # => ["a", "b", "c"]
95
+ ```
96
+
97
+ ### Complex Transformations
98
+
99
+ ```ruby
100
+ # Map operation
101
+ json = '[{"name":"Alice","age":30},{"name":"Bob","age":25}]'
102
+ result = JQ.filter(json, '[.[] | .name]')
103
+ # => "[\"Alice\",\"Bob\"]"
104
+
105
+ # Select operation
106
+ result = JQ.filter(json, '[.[] | select(.age > 26)]')
107
+ # => "[{\"name\":\"Alice\",\"age\":30}]"
108
+
109
+ # Multiple transformations
110
+ result = JQ.filter('{"a":1,"b":2,"c":3}', 'to_entries | map(.value) | add')
111
+ # => "6"
112
+ ```
113
+
114
+ ### Filter Validation
115
+
116
+ Validate a filter before using it:
117
+
118
+ ```ruby
119
+ JQ.validate_filter!('.name')
120
+ # => true
121
+
122
+ JQ.validate_filter!('...invalid')
123
+ # raises JQ::CompileError
124
+ ```
125
+
126
+ ### Error Handling
127
+
128
+ The gem defines four exception classes:
129
+
130
+ ```ruby
131
+ begin
132
+ JQ.filter('invalid json', '.')
133
+ rescue JQ::ParseError => e
134
+ puts "Invalid JSON: #{e.message}"
135
+ end
136
+
137
+ begin
138
+ JQ.filter('{}', '...invalid filter')
139
+ rescue JQ::CompileError => e
140
+ puts "Invalid filter: #{e.message}"
141
+ end
142
+
143
+ begin
144
+ JQ.filter('{}', '.nonexistent.deeply.nested')
145
+ rescue JQ::RuntimeError => e
146
+ puts "Runtime error: #{e.message}"
147
+ end
148
+ ```
149
+
150
+ Exception hierarchy:
151
+
152
+ - `JQ::Error` - Base class for all jq-related errors
153
+ - `JQ::ParseError` - Invalid JSON input
154
+ - `JQ::CompileError` - Invalid jq filter
155
+ - `JQ::RuntimeError` - Runtime execution error
156
+
157
+ ## Thread Safety
158
+
159
+ **Status: Likely safe with jq 1.7+, but not officially guaranteed**
160
+
161
+ This gem creates an isolated `jq_state` for each call, and jq 1.7+ fixed a critical thread-safety bug (PR #2546). Multi-threaded use is **probably safe** in MRI Ruby where the GVL serializes execution, but jq hasn't made formal thread-safety guarantees.
162
+
163
+ **Recommendations:**
164
+ - ✅ Use with jq 1.7+ (check: `jq --version`)
165
+ - ✅ MRI Ruby (standard Ruby) - likely safe due to GVL
166
+ - ⚠️ JRuby/TruffleRuby - use with caution (true parallel threads)
167
+ - 🛡️ Safest for heavy parallel workloads: separate processes
168
+
169
+ See [SECURITY.md](SECURITY.md) for detailed thread safety information.
170
+
171
+ ## Memory Considerations
172
+
173
+ - The gem uses proper jv lifecycle management to prevent memory leaks
174
+ - Very large JSON documents (>100MB) may cause high memory usage
175
+ - Deeply nested structures may hit stack limits
176
+ - Complex filters may be slow - there is no timeout mechanism in v1.0
177
+
178
+ ## Security
179
+
180
+ See [SECURITY.md](SECURITY.md) for detailed security information.
181
+
182
+ Key points:
183
+
184
+ - JSON input is parsed by jq's parser (no eval/injection risk)
185
+ - Filter expressions cannot execute system commands (safe by design)
186
+ - All inputs are validated for type before processing
187
+ - The extension uses proper memory management to prevent buffer overflows
188
+
189
+ ## Development
190
+
191
+ After checking out the repo, run:
192
+
193
+ ```bash
194
+ bundle install
195
+ bundle exec rake compile
196
+ bundle exec rake spec
197
+ ```
198
+
199
+ To check for memory leaks:
200
+
201
+ ```bash
202
+ bundle exec rake compile CFLAGS="-fsanitize=address -g"
203
+ bundle exec rspec spec/memory_spec.rb
204
+ ```
205
+
206
+ ## Contributing
207
+
208
+ Bug reports and pull requests are welcome on GitHub at https://github.com/persona-id/jq-ruby.
209
+
210
+ ## License
211
+
212
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
213
+
214
+ jq itself is licensed under the MIT License. See https://github.com/jqlang/jq for details.
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rake/extensiontask"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ Rake::ExtensionTask.new("jq_ext") do |ext|
10
+ ext.ext_dir = "ext/jq"
11
+ ext.lib_dir = "lib/jq"
12
+ end
13
+
14
+ task spec: :compile
15
+ task default: :spec
data/SECURITY.md ADDED
@@ -0,0 +1,121 @@
1
+ # Security
2
+
3
+ ## Thread Safety
4
+
5
+ **Status: Likely safe with jq 1.7+, but not officially guaranteed**
6
+
7
+ The jq C library was not originally designed for multi-threading. However, as of jq 1.7 (PR #2546), a critical segfault bug in multi-threaded environments was fixed.
8
+
9
+ **Current Safety Profile:**
10
+ - ✅ Each `JQ.filter` call creates its own isolated `jq_state` (no shared state between calls)
11
+ - ✅ jq 1.7+ fixed the thread-local storage segfault (included in your jq 1.8.1)
12
+ - ✅ Ruby's GVL (MRI) prevents true parallel execution, providing additional serialization
13
+ - ⚠️ jq developers have not made formal thread-safety guarantees beyond fixing the segfault
14
+ - ⚠️ Other global state issues may exist but are unconfirmed
15
+
16
+ **Practical Recommendation:**
17
+ - **Probably safe** to call `JQ.filter` from multiple Ruby threads in MRI Ruby with jq 1.7+
18
+ - **Use caution** with JRuby or TruffleRuby where threads can run truly in parallel
19
+ - **Safest approach** for heavy parallel processing: use separate processes (e.g., `parallel` gem)
20
+
21
+ **Version Requirements:**
22
+ - jq 1.7+ strongly recommended for any multi-threaded use
23
+ - Check your jq version: `jq --version`
24
+
25
+ ## Input Validation
26
+
27
+ - **JSON input** is parsed by jq's built-in parser. There is no eval or code injection risk.
28
+ - **Filter expressions** are compiled by jq's compiler. They cannot execute system commands or access the filesystem (safe by design).
29
+ - All inputs are validated for type before processing in the Ruby C extension.
30
+
31
+ ## Memory Safety
32
+
33
+ The extension uses proper jv lifecycle management to prevent memory leaks and buffer overflows:
34
+
35
+ - Every `jv` value is tracked and freed appropriately
36
+ - Error paths ensure cleanup before raising Ruby exceptions
37
+ - The jq library's "consume" pattern is followed correctly
38
+
39
+ ### Testing for Memory Issues
40
+
41
+ Run tests with AddressSanitizer to detect memory errors:
42
+
43
+ ```bash
44
+ bundle exec rake compile CFLAGS="-fsanitize=address -g"
45
+ bundle exec rspec
46
+ ```
47
+
48
+ Or use valgrind:
49
+
50
+ ```bash
51
+ valgrind --leak-check=full bundle exec rspec
52
+ ```
53
+
54
+ Run the memory test suite:
55
+
56
+ ```bash
57
+ bundle exec rspec spec/memory_spec.rb
58
+ ```
59
+
60
+ ## Known Limitations
61
+
62
+ - **Very large JSON documents** (>100MB) may cause high memory usage. The entire document is parsed into memory before processing.
63
+ - **Deeply nested structures** may hit stack limits (typically ~1000 levels depending on system).
64
+ - **Complex filters** may be slow. There is no timeout mechanism in v1.0 - long-running filters will block.
65
+ - **No sandboxing** - While jq filters cannot execute arbitrary code, complex filters can consume significant CPU and memory.
66
+
67
+ ## Security Best Practices
68
+
69
+ 1. **Validate input size** - If processing untrusted JSON, check the size before passing to `JQ.filter`:
70
+
71
+ ```ruby
72
+ MAX_JSON_SIZE = 10 * 1024 * 1024 # 10MB
73
+ raise "JSON too large" if json_string.bytesize > MAX_JSON_SIZE
74
+ ```
75
+
76
+ 2. **Validate filter** - If using user-provided filters, validate them first:
77
+
78
+ ```ruby
79
+ begin
80
+ JQ.validate_filter!(user_filter)
81
+ rescue JQ::CompileError => e
82
+ # Handle invalid filter
83
+ end
84
+ ```
85
+
86
+ 3. **Set timeouts** - Use Ruby's `Timeout` module for long-running operations (note: this may not interrupt C code immediately):
87
+
88
+ ```ruby
89
+ require 'timeout'
90
+
91
+ begin
92
+ Timeout.timeout(5) do
93
+ JQ.filter(json, filter)
94
+ end
95
+ rescue Timeout::Error
96
+ # Handle timeout
97
+ end
98
+ ```
99
+
100
+ 4. **Limit nesting depth** - Pre-validate JSON nesting if processing untrusted input:
101
+
102
+ ```ruby
103
+ def check_nesting_depth(json_string, max_depth = 100)
104
+ depth = 0
105
+ max_seen = 0
106
+ json_string.each_char do |c|
107
+ depth += 1 if c == '{' || c == '['
108
+ depth -= 1 if c == '}' || c == ']'
109
+ max_seen = [max_seen, depth].max
110
+ raise "Nesting too deep" if max_seen > max_depth
111
+ end
112
+ end
113
+ ```
114
+
115
+ ## Reporting Security Issues
116
+
117
+ If you discover a security vulnerability, please email security@persona.com with details. Do not open a public issue.
118
+
119
+ ## Acknowledgments
120
+
121
+ This gem wraps the jq library (https://github.com/jqlang/jq), which is maintained by the jq authors and community.
data/ext/jq/extconf.rb ADDED
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ ENV["RC_ARCHS"] = "" if RUBY_PLATFORM.include?("darwin")
4
+
5
+ require 'mkmf'
6
+ require 'mini_portile2'
7
+
8
+ class JQRecipe < MiniPortile
9
+ JQ_VERSION = '1.8.1'
10
+ JQ_SHA256 = '2be64e7129cecb11d5906290eba10af694fb9e3e7f9fc208a311dc33ca837eb0'
11
+
12
+ def initialize
13
+ super('jq', JQ_VERSION)
14
+ self.files << {
15
+ url: "https://github.com/jqlang/jq/releases/download/jq-#{JQ_VERSION}/jq-#{JQ_VERSION}.tar.gz",
16
+ sha256: JQ_SHA256
17
+ }
18
+ self.configure_options += [
19
+ # "--enable-shared",
20
+ "--enable-static",
21
+ "--enable-all-static",
22
+ "--disable-maintainer-mode",
23
+ "--with-oniguruma=builtin", # Use bundled oniguruma
24
+ "CFLAGS=-fPIC -DJQ_VERSION=\\\"#{JQRecipe::JQ_VERSION}\\\"",
25
+ ]
26
+ end
27
+
28
+ def configure
29
+ return if configured?
30
+
31
+ execute('autoreconf', 'autoreconf -i')
32
+ super
33
+ end
34
+ end
35
+
36
+
37
+ recipe = JQRecipe.new
38
+ recipe.cook
39
+ recipe.activate
40
+ recipe.mkmf_config(pkg: 'oniguruma', static: 'onig')
41
+ recipe.mkmf_config(pkg: 'libjq', static: 'jq')
42
+
43
+ # Verify we can link against libjq with a test program
44
+ checking_for "ability to link against libjq" do
45
+ # Create a test program that uses core jq functions
46
+ src = <<~SRC
47
+ #include <jv.h>
48
+ #include <jq.h>
49
+
50
+ int main(void) {
51
+ // Test that we can link against jq_init, jq_compile, jv_parse, etc.
52
+ jq_state *jq = jq_init();
53
+ if (!jq) return 1;
54
+
55
+ // Test basic jv operations (thread-safe in jq 1.7+)
56
+ jv input = jv_parse("{}");
57
+ int valid = jv_is_valid(input);
58
+ jv_free(input);
59
+
60
+ jq_teardown(&jq);
61
+ return valid ? 0 : 1;
62
+ }
63
+ SRC
64
+
65
+ # Try to link the test program (don't need to run it)
66
+ try_link(src) or abort "Failed to link against libjq"
67
+ end
68
+
69
+ # Add compiler flags
70
+ $CFLAGS << " -Wall -Wextra -Wno-unused-parameter -fPIC"
71
+
72
+ # Enable debug symbols if requested
73
+ if ENV['DEBUG']
74
+ $CFLAGS << " -g -O0"
75
+ else
76
+ $CFLAGS << " -O2"
77
+ end
78
+
79
+ create_makefile('jq/jq_ext')