{"id":31248082,"url":"https://github.com/kyle-williams-1/bsonic","last_synced_at":"2026-01-14T14:52:46.023Z","repository":{"id":315694822,"uuid":"1060494442","full_name":"kyle-williams-1/bsonic","owner":"kyle-williams-1","description":"Parse Lucene-style query syntax into BSON filters for MongoDB — fast, simple, and developer-friendly.","archived":false,"fork":false,"pushed_at":"2025-12-15T20:38:13.000Z","size":4313,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-19T04:35:42.931Z","etag":null,"topics":["bson","golang","lucene","mongodb","query-parser","search"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kyle-williams-1.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-20T02:53:45.000Z","updated_at":"2025-12-15T20:38:09.000Z","dependencies_parsed_at":"2025-09-20T06:18:32.711Z","dependency_job_id":"4ce7e45a-f239-4cd8-a9d0-298f5f98d929","html_url":"https://github.com/kyle-williams-1/bsonic","commit_stats":null,"previous_names":["kyle-williams-1/bsonic"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/kyle-williams-1/bsonic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyle-williams-1%2Fbsonic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyle-williams-1%2Fbsonic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyle-williams-1%2Fbsonic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyle-williams-1%2Fbsonic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kyle-williams-1","download_url":"https://codeload.github.com/kyle-williams-1/bsonic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyle-williams-1%2Fbsonic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28424006,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T13:30:50.153Z","status":"ssl_error","status_checked_at":"2026-01-14T13:29:08.907Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bson","golang","lucene","mongodb","query-parser","search"],"created_at":"2025-09-23T03:01:43.553Z","updated_at":"2026-01-14T14:52:46.016Z","avatar_url":"https://github.com/kyle-williams-1.png","language":"Go","funding_links":[],"categories":["Libraries"],"sub_categories":["Go"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.png\" alt=\"bsonic logo\" width=\"200\"/\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eBSONIC\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  Parse \u003cb\u003eLucene-style query syntax\u003c/b\u003e into \u003cb\u003eBSON filters\u003c/b\u003e for MongoDB — fast, simple, and developer-friendly.\n\u003c/p\u003e\n\n[![CI](https://github.com/kyle-williams-1/bsonic/actions/workflows/ci.yml/badge.svg)](https://github.com/kyle-williams-1/bsonic/actions/workflows/ci.yml)\n[![Integration Tests](https://github.com/kyle-williams-1/bsonic/actions/workflows/integration.yml/badge.svg)](https://github.com/kyle-williams-1/bsonic/actions/workflows/integration.yml)\n[![codecov](https://codecov.io/gh/kyle-williams-1/bsonic/branch/main/graph/badge.svg)](https://codecov.io/gh/kyle-williams-1/bsonic)\n[![Go Report Card](https://goreportcard.com/badge/github.com/kyle-williams-1/bsonic)](https://goreportcard.com/report/github.com/kyle-williams-1/bsonic)\n[![Code scanning alerts](https://github.com/kyle-williams-1/bsonic/workflows/CodeQL/badge.svg)](https://github.com/kyle-williams-1/bsonic/security/code-scanning)\n[![Go Version](https://img.shields.io/badge/Go-1.25+-blue.svg)](https://golang.org/)\n[![Go Reference](https://pkg.go.dev/badge/github.com/kyle-williams-1/bsonic.svg)](https://pkg.go.dev/github.com/kyle-williams-1/bsonic)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\nA Go library that provides Lucene-style syntax for MongoDB BSON filters. Convert human-readable query strings into MongoDB BSON documents that work seamlessly with the official MongoDB Go driver. Built with extensibility in mind, supporting multiple query languages and output formatters.\n\n## Features\n\n- **Lucene-style syntax**: Write queries in familiar Lucene format\n- **Field matching**: Exact matches, wildcard patterns, and regex support\n- **Default fields**: Search across multiple fields using regex patterns (recommended)\n- **Mixed queries**: Combine free text search with field-specific queries\n- **Nested data**: Dot notation for nested fields and array search\n- **Logical operators**: AND, OR, NOT with parentheses grouping\n- **Date \u0026 number queries**: Range queries and comparisons with type-aware parsing\n- **ID field conversion**: Automatic `id` to `_id` field conversion with ObjectID support\n- **MongoDB compatible**: Generates BSON for the official MongoDB Go driver\n- **Extensible**: Easy to add new query languages and output formatters\n\n## Installation\n\n```bash\ngo get github.com/kyle-williams-1/bsonic\n```\n\n## Quick Start\n\nParse Lucene-style queries into MongoDB BSON filters:\n\n```go\nimport (\n    \"github.com/kyle-williams-1/bsonic\"\n    \"go.mongodb.org/mongo-driver/mongo\"\n)\n\n// Parse query and use with MongoDB\nquery, err := bsonic.Parse(\"name:john AND age:25\")\nif err != nil {\n    log.Fatal(err)\n}\n\n// Use directly with MongoDB Find\ncursor, err := collection.Find(ctx, query)\n```\n\nCommon Usage Patterns:\n\n```go\n// Wildcard search\nquery, _ := bsonic.Parse(\"name:Jo*\")\n\n// Regex patterns\nquery, _ := bsonic.Parse(\"email:/.*@example\\\\.com/\")\n\n// Range queries\nquery, _ := bsonic.Parse(\"age:[18 TO 65]\")\n\n// Comparison operators\nquery, _ := bsonic.Parse(\"score:\u003e85\")\nquery, _ := bsonic.Parse(\"created_at:\u003e2024-01-01\")\n\n// Boolean queries\nquery, _ := bsonic.Parse(\"active:true\")\n\n// Logical operators and grouping\nquery, _ := bsonic.Parse(\"(name:john OR name:jane) AND age:25\")\n\n// NOT operator\nquery, _ := bsonic.Parse(\"NOT status:inactive\")\n\n// Nested fields\nquery, _ := bsonic.Parse(\"user.profile.email:john@example.com\")\n\n// Array searches\nquery, _ := bsonic.Parse(\"tags:mongodb\")\n\n// ID conversion (id -\u003e _id with ObjectID)\nquery, _ := bsonic.Parse(\"id:507f1f77bcf86cd799439011\")\n```\n\n## Configuration\n\nBsonic provides flexible configuration options to customize parser behavior. Use configuration when you need to:\n- Set default fields for free text searches\n- Control ID field conversion behavior\n- Customize language and formatter selection\n\nDefault fields enable free text search without requiring MongoDB text indexes. ID conversion simplifies working with MongoDB's `_id` convention.\n\n```go\nimport (\n    \"github.com/kyle-williams-1/bsonic\"\n    \"github.com/kyle-williams-1/bsonic/config\"\n)\n\n// Default configuration (Lucene + MongoDB formatter)\nparser := bsonic.New()\n\n// Custom configuration with default fields\ncfg := config.Default().\n    WithLanguage(config.LanguageLucene).\n    WithFormatter(config.FormatterMongo).\n    WithDefaultFields([]string{\"name\", \"description\", \"title\"}).\n    WithReplaceIDWithMongoID(true).      // Convert \"id\" to \"_id\" (default: true)\n    WithAutoConvertIDToObjectID(true)     // Convert string to ObjectID (default: true)\n\nparser, _ := bsonic.NewWithConfig(cfg)\n\n// Now free text queries search across name, description, and title\nquery, _ := parser.Parse(\"engineer\")\n```\n\n**Configuration Options:**\n- `WithDefaultFields([]string)`: Fields to search for free text queries\n- `WithReplaceIDWithMongoID(bool)`: Convert `id` field names to `_id` (default: `true`)\n- `WithAutoConvertIDToObjectID(bool)`: Convert string values to `primitive.ObjectID` (default: `true`)\n\n## Query Syntax\n\n### String Search\n\nExact string matching with support for quoted phrases. Field queries are case-sensitive.\n\n```go\n// Exact match\nquery, _ := bsonic.Parse(\"name:john\")\n// Output:\n{\n  \"name\": \"john\"\n}\n\n// Quoted values with spaces\nquery, _ := bsonic.Parse(`name:\"john doe\"`)\n// Output:\n{\n  \"name\": \"john doe\"\n}\n```\n\n**Note:** For case-insensitive searches, use default fields with free text (see Default Fields section).\n\n### Wildcard Patterns\n\nUse `*` to match any sequence of characters. Wildcards are case-sensitive.\n\n```go\n// Starts with pattern\nquery, _ := bsonic.Parse(\"name:Jo*\")\n// Output:\n{\n  \"name\": {\n    \"$regex\": \"^Jo.*\"\n  }\n}\n```\n\n### Regex Patterns\n\nWrap patterns in forward slashes `/pattern/`. Bsonic automatically adds anchors for exact matching unless already present.\n\n```go\n// Basic regex pattern\nquery, _ := bsonic.Parse(\"email:/.*@example\\\\.com/\")\n// Output:\n{\n  \"email\": {\n    \"$regex\": \"^.*@example\\\\.com$\"\n  }\n}\n\n// Complex pattern\nquery, _ := bsonic.Parse(\"phone:/^\\\\+?[1-9]\\\\d{1,14}$/\")\n// Output:\n{\n  \"phone\": {\n    \"$regex\": \"^\\\\+?[1-9]\\\\d{1,14}$\"\n  }\n}\n```\n\n**Note:** Regex patterns are case-sensitive. Anchors (`^` and `$`) are automatically added if not present.\n\n### Primitive ID Conversion\n\nBsonic automatically detects fields ending with `_id` (including `id` which converts to `_id`) and converts valid 24-character hex strings to `primitive.ObjectID`. Invalid ObjectIDs fall back to string matching. All query patterns (regex, wildcards, ranges) work on ID fields when ObjectID conversion isn't applicable.\n\n```go\n// ObjectID conversion\nquery, _ := bsonic.Parse(\"id:507f1f77bcf86cd799439011\")\n// Output:\n{\n  \"_id\": ObjectID(\"507f1f77bcf86cd799439011\")\n}\n\n// Fields ending with _id are automatically detected\nquery, _ := bsonic.Parse(\"user_id:507f1f77bcf86cd799439011\")\n// Output:\n{\n  \"user_id\": ObjectID(\"507f1f77bcf86cd799439011\")\n}\n\n// Invalid ObjectID falls back to string search\nquery, _ := bsonic.Parse(\"id:invalid-hex\")\n// Output:\n{\n  \"_id\": \"invalid-hex\"\n}\n```\n\n**Configuration:** ID field name conversion (`id` → `_id`) and ObjectID conversion are configurable via `WithReplaceIDWithMongoID()` and `WithAutoConvertIDToObjectID()`.\n\n### Date Queries \u0026 Ranges\n\nBsonic automatically detects and parses dates in various formats. Use range syntax `[start TO end]` and comparison operators `\u003e`, `\u003c`, `\u003e=`, `\u003c=`.\n\n**Supported Date Formats:** `2023-01-15`, `2023-01-15T10:30:00Z`, `2023-01-15T10:30:00`, `2023-01-15 10:30:00`, `01/15/2023`, `2023/01/15`\n\n```go\n// Single date\nquery, _ := bsonic.Parse(\"created_at:2023-01-15\")\n// Output:\n{\n  \"created_at\": \"2023-01-15 00:00:00 +0000 UTC\"\n}\n\n// Date range\nquery, _ := bsonic.Parse(\"created_at:[2023-01-01 TO 2023-12-31]\")\n// Output:\n{\n  \"created_at\": {\n    \"$gte\": \"2023-01-01 00:00:00 +0000 UTC\",\n    \"$lte\": \"2023-12-31 00:00:00 +0000 UTC\"\n  }\n}\n\n// Comparison operators\nquery, _ := bsonic.Parse(\"created_at:\u003e2024-01-01\")\n// Output:\n{\n  \"created_at\": {\n    \"$gt\": \"2024-01-01 00:00:00 +0000 UTC\"\n  }\n}\n\n// Open-ended range\nquery, _ := bsonic.Parse(\"created_at:[* TO 2023-12-31]\")\n// Output:\n{\n  \"created_at\": {\n    \"$lte\": \"2023-12-31 00:00:00 +0000 UTC\"\n  }\n}\n```\n\n### Number Queries \u0026 Ranges\n\nNumbers are automatically detected and parsed. Supports integers, floats, ranges, and comparisons.\n\n```go\n// Integer\nquery, _ := bsonic.Parse(\"age:25\")\n// Output:\n{\n  \"age\": 25\n}\n\n// Number range\nquery, _ := bsonic.Parse(\"age:[18 TO 65]\")\n// Output:\n{\n  \"age\": {\n    \"$gte\": 18,\n    \"$lte\": 65\n  }\n}\n\n// Comparison operators\nquery, _ := bsonic.Parse(\"score:\u003e85\")\n// Output:\n{\n  \"score\": {\n    \"$gt\": 85\n  }\n}\n\n// Float range\nquery, _ := bsonic.Parse(\"price:[10.50 TO 99.99]\")\n// Output:\n{\n  \"price\": {\n    \"$gte\": 10.5,\n    \"$lte\": 99.99\n  }\n}\n```\n\n### Boolean Queries\n\nBoolean values are automatically detected and converted to Go boolean types.\n\n```go\nquery, _ := bsonic.Parse(\"active:true\")\n// Output:\n{\n  \"active\": true\n}\n```\n\n### Nested Data Search\n\nUse dot notation to query nested fields. Works with all query types.\n\n```go\n// Nested field\nquery, _ := bsonic.Parse(\"user.profile.email:john@example.com\")\n// Output:\n{\n  \"user.profile.email\": \"john@example.com\"\n}\n\n// Nested with range\nquery, _ := bsonic.Parse(\"user.profile.age:[18 TO 65]\")\n// Output:\n{\n  \"user.profile.age\": {\n    \"$gte\": 18,\n    \"$lte\": 65\n  }\n}\n```\n\n### Array Searches\n\nQuery array fields like any other field. MongoDB automatically matches array elements.\n\n```go\n// Array field search\nquery, _ := bsonic.Parse(\"tags:mongodb\")\n// Output:\n{\n  \"tags\": \"mongodb\"\n}\n\n// Array with multiple values\nquery, _ := bsonic.Parse(\"tags:mongodb OR tags:go\")\n// Output:\n{\n  \"$or\": [\n    {\n      \"tags\": \"mongodb\"\n    },\n    {\n      \"tags\": \"go\"\n    }\n  ]\n}\n```\n\n### Logical Operators\n\nCombine conditions using `AND` and `OR` operators. **Operator Precedence:** `NOT` \u003e `AND` \u003e `OR`\n\n```go\n// AND operator\nquery, _ := bsonic.Parse(\"name:john AND age:25\")\n// Output:\n{\n  \"age\": 25,\n  \"name\": \"john\"\n}\n\n// OR operator\nquery, _ := bsonic.Parse(\"name:john OR name:jane\")\n// Output:\n{\n  \"$or\": [\n    {\n      \"name\": \"john\"\n    },\n    {\n      \"name\": \"jane\"\n    }\n  ]\n}\n\n// Complex AND/OR combination\nquery, _ := bsonic.Parse(\"name:john AND (age:25 OR age:30)\")\n// Output:\n{\n  \"$and\": [\n    {\n      \"name\": \"john\"\n    },\n    {\n      \"$or\": [\n        {\n          \"age\": 25\n        },\n        {\n          \"age\": 30\n        }\n      ]\n    }\n  ]\n}\n```\n\n### NOT Operator\n\nNegate conditions using the `NOT` operator. Bsonic applies De Morgan's law for complex negations.\n\n```go\n// Simple NOT\nquery, _ := bsonic.Parse(\"NOT status:inactive\")\n// Output:\n{\n  \"status\": {\n    \"$ne\": \"inactive\"\n  }\n}\n\n// NOT with OR (applies De Morgan's law)\nquery, _ := bsonic.Parse(\"NOT (name:john OR name:jane)\")\n// Output:\n{\n  \"$and\": [\n    {\n      \"name\": {\n        \"$ne\": \"john\"\n      }\n    },\n    {\n      \"name\": {\n        \"$ne\": \"jane\"\n      }\n    }\n  ]\n}\n\n// NOT with regex (uses $not operator)\nquery, _ := bsonic.Parse(\"NOT name:/john/\")\n// Output:\n{\n  \"name\": {\n    \"$not\": {\n      \"$regex\": \"^john$\"\n    }\n  }\n}\n```\n\n### Grouping with Parentheses\n\nUse parentheses to control operator precedence. Nested parentheses are supported.\n\n```go\n// Basic grouping\nquery, _ := bsonic.Parse(\"(name:john OR name:jane) AND age:25\")\n// Output:\n{\n  \"$and\": [\n    {\n      \"$or\": [\n        {\n          \"name\": \"john\"\n        },\n        {\n          \"name\": \"jane\"\n        }\n      ]\n    },\n    {\n      \"age\": 25\n    }\n  ]\n}\n\n// Complex nested query\nquery, _ := bsonic.Parse(\"(name:jo* OR name:ja*) AND (age:[18 TO 65] OR role:admin)\")\n// Output:\n{\n  \"$and\": [\n    {\n      \"$or\": [\n        {\n          \"name\": {\n            \"$regex\": \"^jo.*\"\n          }\n        },\n        {\n          \"name\": {\n            \"$regex\": \"^ja.*\"\n          }\n        }\n      ]\n    },\n    {\n      \"$or\": [\n        {\n          \"age\": {\n            \"$gte\": 18,\n            \"$lte\": 65\n          }\n        },\n        {\n          \"role\": \"admin\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Default Fields\n\nDefault fields enable free text search across multiple fields without requiring MongoDB text indexes. Free text searches are case-insensitive by default, unless regex or wildcards are used.\n\n```go\n// Multiple default fields\nquery, _ := bsonic.ParseWithDefaults([]string{\"name\", \"description\"}, \"engineer\")\n// Output:\n{\n  \"$or\": [\n    {\n      \"name\": {\n        \"$regex\": \"^engineer$\",\n        \"$options\": \"i\"\n      }\n    },\n    {\n      \"description\": {\n        \"$regex\": \"^engineer$\",\n        \"$options\": \"i\"\n      }\n    }\n  ]\n}\n\n// Multiple words (each word searches all default fields with OR)\nquery, _ := bsonic.ParseWithDefaults([]string{\"name\", \"title\"}, \"software engineer\")\n// Output:\n{\n  \"$or\": [\n    {\n      \"name\": {\n        \"$regex\": \"^software$\",\n        \"$options\": \"i\"\n      }\n    },\n    {\n      \"title\": {\n        \"$regex\": \"^software$\",\n        \"$options\": \"i\"\n      }\n    },\n    {\n      \"name\": {\n        \"$regex\": \"^engineer$\",\n        \"$options\": \"i\"\n      }\n    },\n    {\n      \"title\": {\n        \"$regex\": \"^engineer$\",\n        \"$options\": \"i\"\n      }\n    }\n  ]\n}\n\n// Quoted phrase (treated as single term)\nquery, _ := bsonic.ParseWithDefaults([]string{\"name\"}, `\"john doe\"`)\n// Output:\n{\n  \"name\": {\n    \"$regex\": \"^john doe$\",\n    \"$options\": \"i\"\n  }\n}\n\n// Configuration-based default fields\ncfg := config.Default().\n    WithDefaultFields([]string{\"name\", \"description\", \"title\"})\nparser, _ := bsonic.NewWithConfig(cfg)\nquery, _ := parser.Parse(\"engineer\")\n```\n\n### Mixed Default Field and Structured Queries\n\nCombine free text search with structured field queries. By default, they are combined with OR unless explicit operators are used.\n\n```go\n// Mixed query (defaults to OR)\nquery, _ := bsonic.ParseWithDefaults([]string{\"role\"}, \"name:john admin\")\n// Output:\n{\n  \"$or\": [\n    {\n      \"name\": \"john\"\n    },\n    {\n      \"role\": {\n        \"$regex\": \"^admin$\",\n        \"$options\": \"i\"\n      }\n    }\n  ]\n}\n\n// Mixed query with explicit AND\nquery, _ := bsonic.ParseWithDefaults([]string{\"name\"}, \"john AND role:admin\")\n// Output:\n{\n  \"$and\": [\n    {\n      \"name\": {\n        \"$regex\": \"^john$\",\n        \"$options\": \"i\"\n      }\n    },\n    {\n      \"role\": \"admin\"\n    }\n  ]\n}\n```\n\n## Extensible Architecture\n\nBsonic supports multiple query languages and output formatters through a modular design.\n\n### Package Structure\n\n```\nbsonic/\n├── config/           # Configuration types\n├── language/lucene/  # Lucene query parser\n├── formatter/mongo/  # MongoDB BSON output formatter\n└── bsonic.go         # Main API\n```\n\n**Adding New Languages/Formatters:** Implement the `language.Parser` or `formatter.Formatter` interfaces.\n\n## Error Handling \u0026 Performance\n\n```go\n// Safe parsing with error handling\nfunc parseQuerySafely(query string) (bson.M, error) {\n    result, err := bsonic.Parse(query)\n    if err != nil {\n        return nil, fmt.Errorf(\"failed to parse query '%s': %w\", query, err)\n    }\n    return result, nil\n}\n\n// For high-performance applications, reuse parser instances\nvar globalParser = bsonic.New()\n\nfunc handleRequest(queryStr string) (bson.M, error) {\n    return globalParser.Parse(queryStr)\n}\n```\n\n## Examples \u0026 Testing\n\n- [Examples](examples/) - Detailed usage examples\n- [Integration Tests](tests/README.md) - MongoDB integration testing guide\n\n## Contributing\n\nContributions welcome! See [DEPENDENCIES.md](DEPENDENCIES.md) for development setup.\n\n**Requirements:** Go 1.25+, golangci-lint, Docker (for integration tests)\n\n## License\n\nApache License 2.0 - see [LICENSE](LICENSE) for details.\n\n## Links\n\n- [Changelog](CHANGELOG.md) - Recent changes and features\n- [Dependencies](DEPENDENCIES.md) - Required and optional dependencies\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyle-williams-1%2Fbsonic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkyle-williams-1%2Fbsonic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyle-williams-1%2Fbsonic/lists"}