json-rescue 0.2.2 → 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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,116 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.0](https://github.com/azeemmirza/json-rescue/compare/0.2.2...1.0.0) (2026-02-20)
4
+
5
+ ### ✨ Features
6
+
7
+ - **Stable API Contract**: Finalized and stable public API for production use
8
+ - **Comprehensive Repair Suite**: Complete set of repair strategies for common JSON defects
9
+ - Trailing comma removal
10
+ - JSONC comment removal (single and multi-line)
11
+ - Smart quotes conversion
12
+ - **NEW**: Single quote to double quote conversion
13
+ - **NEW**: Unquoted key addition (converts `{key: value}` to `{"key": value}`)
14
+ - **NEW**: Python literal conversion (True/False/None → true/false/null)
15
+
16
+ - **Candidate Scoring System**: Each result now includes a confidence score (0-1)
17
+ - Perfect JSON (no repairs): score ≈ 1.0
18
+ - JSON requiring repairs: score penalized by repair count and type
19
+ - Failures: score = 0
20
+
21
+ - **Best Mode Selection**: New `mode: 'best'` option to automatically select highest-scoring candidate
22
+ - Useful when multiple JSON candidates are found
23
+ - Automatically chooses most reliable extraction
24
+
25
+ - **Convenience API**: New `rescueJsonAll()` function for easier multi-candidate extraction
26
+ - Simpler alternative to `rescueJson(text, { mode: 'all' })`
27
+ - Type-safe with full generic support
28
+
29
+ ### 🔧 Technical Improvements
30
+
31
+ - **Enhanced Type Definitions**: Score field added to RescueResult
32
+ - **Improved Scoring Algorithm**: Takes into account repair count and text length
33
+ - **Comprehensive Test Suite**: 94 tests covering all features and edge cases
34
+ - **Zero Dependencies**: Remains dependency-free
35
+
36
+ ### 📊 Test Coverage
37
+
38
+ - **Total Tests**: 94 (up from 56)
39
+ - **Test Suites**: 4/4 passing ✅
40
+ - **Extraction Tests**: 10 tests
41
+ - **Repair Tests**: 30 tests (15 new)
42
+ - **Integration Tests**: 54 tests (38 new)
43
+
44
+ ### 📝 Documentation
45
+
46
+ All features are fully documented with:
47
+ - JSDoc comments for all public APIs
48
+ - TypeScript type definitions
49
+ - Usage examples
50
+ - Behavior guarantees
51
+
52
+ ### ✅ v1.0.0 Release Checklist
53
+
54
+ - [x] All v0.1.0 core features
55
+ - [x] All v0.2.0 repair expansions
56
+ - [x] Candidate scoring system
57
+ - [x] Multiple extraction modes (first, all, best)
58
+ - [x] Stable issue codes and contract
59
+ - [x] Comprehensive test coverage
60
+ - [x] Type-safe APIs with generics
61
+ - [x] Production-ready error handling
62
+ - [x] Zero external dependencies
63
+
64
+ ### 🚀 What's Included
65
+
66
+ **Core Extraction:**
67
+ - Markdown fence extraction (```json ... ```)
68
+ - String-aware balanced brace extraction
69
+ - Automatic candidate deduplication
70
+
71
+ **Automatic Repairs:**
72
+ - Trailing comma removal
73
+ - JSONC comment removal
74
+ - Smart quotes conversion
75
+ - Single quote conversion
76
+ - Unquoted key handling
77
+ - Python literal conversion
78
+
79
+ **Parsing & Results:**
80
+ - Generic type support for type-safe parsing
81
+ - Transparent repair reporting with issue codes
82
+ - Confidence scoring for result evaluation
83
+ - Multiple extraction modes for flexibility
84
+ - Detailed error messages
85
+
86
+ ### 💡 Usage Example
87
+
88
+ ```typescript
89
+ import { rescueJson, rescueJsonAll } from 'json-rescue';
90
+
91
+ // Simple usage (first valid result)
92
+ const result = rescueJson<MyType>(mixedText);
93
+ if (result.success) {
94
+ console.log('Parsed:', result.data);
95
+ console.log('Repairs:', result.issues);
96
+ }
97
+
98
+ // Get best result (highest confidence score)
99
+ const best = rescueJson<MyType>(mixedText, { mode: 'best' });
100
+
101
+ // Get all candidates
102
+ const all = rescueJsonAll<MyType>(mixedText);
103
+ ```
104
+
105
+ ### 🎯 Production Ready
106
+
107
+ This release marks json-rescue as production-ready with:
108
+ - Stable public API
109
+ - Comprehensive error handling
110
+ - Full TypeScript support
111
+ - Extensive test coverage
112
+ - Zero breaking changes planned for 1.x
113
+
114
+ ---
115
+
3
116
  ## [0.2.1](https://github.com/azeemmirza/json-rescue/compare/0.2.0...0.2.1) (2026-02-20)
package/README.md CHANGED
@@ -12,22 +12,24 @@
12
12
  | Item | Value |
13
13
  |------|-------|
14
14
  | Package Name | `json-rescue` |
15
- | Target Version | 0.1.0 (Initial public release) |
15
+ | Current Version | **1.0.0** (Stable Release) |
16
16
  | License | MIT |
17
17
  | Dependencies | Zero Dependency |
18
18
  | Primary Goal | Recover strict JSON from mixed / malformed text safely |
19
19
 
20
- ### 1.2 Current Features (Planned for Initial Releases)
20
+ ### 1.2 Current Features (v1.0.0 - Production Ready)
21
21
 
22
22
  - ✅ Extract JSON from Markdown code blocks (```json … ```)
23
23
  - ✅ Extract JSON from plain text using balanced braces / brackets
24
- - ✅ Auto-repair (trailing commas, comments, smart quotes; more planned)
25
- - ✅ TypeScript generics support
26
- - ✅ Multiple JSON extraction (`mode: 'all'`)
24
+ - ✅ Auto-repair (trailing commas, JSONC comments, smart quotes, single quotes, unquoted keys, Python literals)
25
+ - ✅ TypeScript generics support with full type safety
26
+ - ✅ Multiple JSON extraction modes (`first`, `all`, `best`)
27
27
  - ✅ Repair report (issues list with codes + metadata)
28
- - Streaming / incremental extraction (planned)
29
- - Field extraction without full parsing (planned)
30
- - ⏳ Schema validation (explicitly out-of-scope for early versions; optional later)
28
+ - Candidate scoring and confidence ranking
29
+ - Convenient API (`rescueJson` and `rescueJsonAll`)
30
+ - ⏳ Streaming / incremental extraction (planned for v1.1)
31
+ - ⏳ Field extraction without full parsing (planned for v1.2)
32
+ - ⏳ Schema validation (planned for v2.0)
31
33
 
32
34
  ### 1.3 Proposal Background
33
35
 
@@ -59,13 +61,13 @@ Typical environments where this breaks:
59
61
 
60
62
  | Priority | Feature | Importance | Status |
61
63
  |----------|---------|------------|--------|
62
- | 1 | Deterministic extraction from mixed text | ⭐⭐⭐ Highest | ✅ Planned (v0.1.0) |
63
- | 2 | Repair report with issue codes | ⭐⭐⭐ Highest | ✅ Planned (v0.1.0) |
64
- | 3 | Safe auto-repair for common defects | ⭐⭐ High | ✅ Planned (v0.1.0 → v0.2.0) |
65
- | 4 | Multiple JSON extraction (`all`) | ⭐⭐ High | ✅ Planned (v0.1.0/v0.2.0) |
66
- | 5 | Candidate scoring (`best`) | ⭐⭐ Medium | ✅ Planned (v0.2.0) |
67
- | 6 | Streaming/incremental parsing | ⭐ Medium | ⏳ Planned (v0.4.0) |
68
- | 7 | Field extraction API | ⭐ Low | ⏳ Planned (v0.4.0) |
64
+ | 1 | Deterministic extraction from mixed text | ⭐⭐⭐ Highest | ✅ v1.0.0 |
65
+ | 2 | Repair report with issue codes | ⭐⭐⭐ Highest | ✅ v1.0.0 |
66
+ | 3 | Safe auto-repair for common defects | ⭐⭐ High | ✅ v1.0.0 |
67
+ | 4 | Multiple JSON extraction (`all` and `best`) | ⭐⭐ High | ✅ v1.0.0 |
68
+ | 5 | Candidate scoring and best selection | ⭐⭐ Medium | ✅ v1.0.0 |
69
+ | 6 | Streaming/incremental parsing | ⭐ Medium | ⏳ v1.1+ |
70
+ | 7 | Field extraction API | ⭐ Low | ⏳ v1.2+ |
69
71
 
70
72
  ### 2.3 Expected Benefits
71
73
 
@@ -79,32 +81,32 @@ Typical environments where this breaks:
79
81
 
80
82
  ## 3. Implementation Status
81
83
 
82
- `json-rescue` is designed to ship fast in a staged roadmap, prioritizing the stable core first.
84
+ `json-rescue` is at **v1.0.0** - Production Ready. All core features are complete and stable.
83
85
 
84
- ### 3.1 Version Roadmap (Planned)
86
+ ### 3.1 Version Roadmap (Completed)
85
87
 
86
88
  ```text
87
- v0.1.0 (Core) → v0.2.1 → v0.3.0 → v0.4.0 → v1.0.0
89
+ v0.1.0 (Core) → v0.2.0 → v0.3.0 → v1.0.0 → v1.1.0+
88
90
  │ │ │ │ │
89
91
  ▼ ▼ ▼ ▼ ▼
90
- Extract + Repair Multi + Streaming Stable
91
- Report Expansion Scoring + Fields Contract
92
+ Extract + Repair Multi + Stable Advanced
93
+ Report Expansion Scoring Contract Features
92
94
  ```
93
95
 
94
- ## 3.2 Planned Features by Version
96
+ ### 3.2 Feature Status by Version
95
97
 
96
98
  | Version | Feature | Status |
97
99
  |--------:|---------|:------|
98
- | v0.1.0 | Markdown fence extraction | ✅ Planned |
99
- | v0.1.0 | Balanced brace extraction (string-aware) | ✅ Planned |
100
- | v0.1.0 | Repairs: trailing commas, JSONC comments, smart quotes | ✅ Planned |
101
- | v0.1.0 | Repair report (`issues[]`) | ✅ Planned |
102
- | v0.2.0 | Repairs: single quotes, unquoted keys, Python literals | Planned |
103
- | v0.2.0 | Candidate scoring (mode: `'best'`) | Planned |
104
- | v0.3.0 | `rescueJsonAll()` convenience | Planned |
105
- | v0.4.0 | Streaming / incremental candidate tracking | Planned |
106
- | v0.4.0 | Field extraction (optional, streaming-friendly) | ⏳ Planned |
107
- | v1.0.0 | Behavior contract + stable issue codes | ⏳ Planned |
100
+ | v0.1.0 | Markdown fence extraction | ✅ v1.0.0 |
101
+ | v0.1.0 | Balanced brace extraction (string-aware) | ✅ v1.0.0 |
102
+ | v0.1.0 | Repairs: trailing commas, JSONC comments, smart quotes | ✅ v1.0.0 |
103
+ | v0.1.0 | Repair report (`issues[]`) | ✅ v1.0.0 |
104
+ | v0.2.0 | Repairs: single quotes, unquoted keys, Python literals | v1.0.0 |
105
+ | v0.2.0 | Candidate scoring (mode: `'best'`) | v1.0.0 |
106
+ | v0.3.0 | `rescueJsonAll()` convenience | v1.0.0 |
107
+ | v1.0.0 | Behavior contract + stable issue codes | v1.0.0 |
108
+ | v1.1.0 | Streaming / incremental candidate tracking | ⏳ Planned |
109
+ | v1.2.0 | Field extraction (optional, streaming-friendly) | ⏳ Planned |
108
110
 
109
111
  # License
110
112
  `json-rescue` is released under the **MIT License**.
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  * json-rescue - Extract, repair, and parse JSON from messy real-world text
3
3
  * @packageDocumentation
4
4
  */
5
- export { rescueJson } from './rescue';
5
+ export { rescueJson, rescueJsonAll } from './rescue';
6
6
  export type { RescueResult, RescueOptions, RepairIssue, ExtractionCandidate } from './types';
7
7
  export { extractAllCandidates, extractFromMarkdown, extractBalancedBraces } from './extraction';
8
- export { autoRepair, repairTrailingCommas, repairJsoncComments, repairSmartQuotes } from './repair';
8
+ export { autoRepair, repairTrailingCommas, repairJsoncComments, repairSmartQuotes, repairSingleQuotes, repairUnquotedKeys, repairPythonLiterals, } from './repair';
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAG7F,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGhG,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACrD,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAG7F,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGhG,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -4,9 +4,10 @@
4
4
  * @packageDocumentation
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.repairSmartQuotes = exports.repairJsoncComments = exports.repairTrailingCommas = exports.autoRepair = exports.extractBalancedBraces = exports.extractFromMarkdown = exports.extractAllCandidates = exports.rescueJson = void 0;
7
+ exports.repairPythonLiterals = exports.repairUnquotedKeys = exports.repairSingleQuotes = exports.repairSmartQuotes = exports.repairJsoncComments = exports.repairTrailingCommas = exports.autoRepair = exports.extractBalancedBraces = exports.extractFromMarkdown = exports.extractAllCandidates = exports.rescueJsonAll = exports.rescueJson = void 0;
8
8
  var rescue_1 = require("./rescue");
9
9
  Object.defineProperty(exports, "rescueJson", { enumerable: true, get: function () { return rescue_1.rescueJson; } });
10
+ Object.defineProperty(exports, "rescueJsonAll", { enumerable: true, get: function () { return rescue_1.rescueJsonAll; } });
10
11
  // Re-export extraction utilities
11
12
  var extraction_1 = require("./extraction");
12
13
  Object.defineProperty(exports, "extractAllCandidates", { enumerable: true, get: function () { return extraction_1.extractAllCandidates; } });
@@ -18,4 +19,7 @@ Object.defineProperty(exports, "autoRepair", { enumerable: true, get: function (
18
19
  Object.defineProperty(exports, "repairTrailingCommas", { enumerable: true, get: function () { return repair_1.repairTrailingCommas; } });
19
20
  Object.defineProperty(exports, "repairJsoncComments", { enumerable: true, get: function () { return repair_1.repairJsoncComments; } });
20
21
  Object.defineProperty(exports, "repairSmartQuotes", { enumerable: true, get: function () { return repair_1.repairSmartQuotes; } });
22
+ Object.defineProperty(exports, "repairSingleQuotes", { enumerable: true, get: function () { return repair_1.repairSingleQuotes; } });
23
+ Object.defineProperty(exports, "repairUnquotedKeys", { enumerable: true, get: function () { return repair_1.repairUnquotedKeys; } });
24
+ Object.defineProperty(exports, "repairPythonLiterals", { enumerable: true, get: function () { return repair_1.repairPythonLiterals; } });
21
25
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,mCAAsC;AAA7B,oGAAA,UAAU,OAAA;AAGnB,iCAAiC;AACjC,2CAAgG;AAAvF,kHAAA,oBAAoB,OAAA;AAAE,iHAAA,mBAAmB,OAAA;AAAE,mHAAA,qBAAqB,OAAA;AAEzE,6BAA6B;AAC7B,mCAAoG;AAA3F,oGAAA,UAAU,OAAA;AAAE,8GAAA,oBAAoB,OAAA;AAAE,6GAAA,mBAAmB,OAAA;AAAE,2GAAA,iBAAiB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,mCAAqD;AAA5C,oGAAA,UAAU,OAAA;AAAE,uGAAA,aAAa,OAAA;AAGlC,iCAAiC;AACjC,2CAAgG;AAAvF,kHAAA,oBAAoB,OAAA;AAAE,iHAAA,mBAAmB,OAAA;AAAE,mHAAA,qBAAqB,OAAA;AAEzE,6BAA6B;AAC7B,mCAQkB;AAPhB,oGAAA,UAAU,OAAA;AACV,8GAAA,oBAAoB,OAAA;AACpB,6GAAA,mBAAmB,OAAA;AACnB,2GAAA,iBAAiB,OAAA;AACjB,4GAAA,kBAAkB,OAAA;AAClB,4GAAA,kBAAkB,OAAA;AAClB,8GAAA,oBAAoB,OAAA"}
package/dist/repair.d.ts CHANGED
@@ -25,6 +25,22 @@ export declare function repairJsoncComments(text: string): RepairResult;
25
25
  * e.g., "hello" → "hello"
26
26
  */
27
27
  export declare function repairSmartQuotes(text: string): RepairResult;
28
+ /**
29
+ * Replace single quotes with double quotes for JSON keys and string values
30
+ * e.g., {'key': 'value'} → {"key": "value"}
31
+ * Note: Only replaces quotes around identifiers and string literals at top level
32
+ */
33
+ export declare function repairSingleQuotes(text: string): RepairResult;
34
+ /**
35
+ * Add quotes around unquoted object keys
36
+ * e.g., {key: "value"} → {"key": "value"}
37
+ */
38
+ export declare function repairUnquotedKeys(text: string): RepairResult;
39
+ /**
40
+ * Convert Python literal syntax to JSON
41
+ * e.g., True → true, False → false, None → null
42
+ */
43
+ export declare function repairPythonLiterals(text: string): RepairResult;
28
44
  /**
29
45
  * Check if text is valid JSON without throwing
30
46
  */
@@ -1 +1 @@
1
- {"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../src/repair.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAiBrD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAkB/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA2B9D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAmB5D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOjD"}
1
+ {"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../src/repair.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAwBrD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAkB/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA2B9D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAmB5D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA+B7D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAyB7D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAgC/D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOjD"}
package/dist/repair.js CHANGED
@@ -7,6 +7,9 @@ exports.autoRepair = autoRepair;
7
7
  exports.repairTrailingCommas = repairTrailingCommas;
8
8
  exports.repairJsoncComments = repairJsoncComments;
9
9
  exports.repairSmartQuotes = repairSmartQuotes;
10
+ exports.repairSingleQuotes = repairSingleQuotes;
11
+ exports.repairUnquotedKeys = repairUnquotedKeys;
12
+ exports.repairPythonLiterals = repairPythonLiterals;
10
13
  exports.isValidJson = isValidJson;
11
14
  /**
12
15
  * Apply all default repairs to the text
@@ -15,7 +18,14 @@ function autoRepair(text) {
15
18
  let current = text;
16
19
  const allIssues = [];
17
20
  // Apply repairs in order
18
- const repairs = [repairTrailingCommas, repairJsoncComments, repairSmartQuotes];
21
+ const repairs = [
22
+ repairTrailingCommas,
23
+ repairJsoncComments,
24
+ repairSmartQuotes,
25
+ repairSingleQuotes,
26
+ repairUnquotedKeys,
27
+ repairPythonLiterals,
28
+ ];
19
29
  for (const repair of repairs) {
20
30
  const result = repair(current);
21
31
  current = result.text;
@@ -96,6 +106,98 @@ function repairSmartQuotes(text) {
96
106
  .replace(/[\u2018\u2019]/g, "'"); // Convert curly single quotes
97
107
  return { text: repaired, issues };
98
108
  }
109
+ /**
110
+ * Replace single quotes with double quotes for JSON keys and string values
111
+ * e.g., {'key': 'value'} → {"key": "value"}
112
+ * Note: Only replaces quotes around identifiers and string literals at top level
113
+ */
114
+ function repairSingleQuotes(text) {
115
+ const issues = [];
116
+ let inDoubleQuote = false;
117
+ let result = '';
118
+ let modified = false;
119
+ for (let i = 0; i < text.length; i++) {
120
+ const char = text[i];
121
+ // Track if we're in a double-quoted string
122
+ if (char === '"' && (i === 0 || text[i - 1] !== '\\')) {
123
+ inDoubleQuote = !inDoubleQuote;
124
+ result += char;
125
+ }
126
+ else if (!inDoubleQuote && char === "'" && (i === 0 || text[i - 1] !== '\\')) {
127
+ // Replace single quotes with double quotes when not already in a double-quoted string
128
+ result += '"';
129
+ modified = true;
130
+ }
131
+ else {
132
+ result += char;
133
+ }
134
+ }
135
+ if (modified) {
136
+ issues.push({
137
+ code: 'SINGLE_QUOTES',
138
+ message: 'Converted single quotes to double quotes',
139
+ severity: 'warning',
140
+ });
141
+ }
142
+ return { text: result, issues };
143
+ }
144
+ /**
145
+ * Add quotes around unquoted object keys
146
+ * e.g., {key: "value"} → {"key": "value"}
147
+ */
148
+ function repairUnquotedKeys(text) {
149
+ const issues = [];
150
+ // Match unquoted keys: word characters followed by colon
151
+ // But not inside strings
152
+ let result = text;
153
+ let modified = false;
154
+ // Simple regex to find unquoted keys - matches word boundaries before colons
155
+ const unquotedKeyRegex = /([{,]\s*)([a-zA-Z_$][a-zA-Z0-9_$]*)\s*:/g;
156
+ if (unquotedKeyRegex.test(result)) {
157
+ modified = true;
158
+ result = result.replace(unquotedKeyRegex, '$1"$2":');
159
+ }
160
+ if (modified) {
161
+ issues.push({
162
+ code: 'UNQUOTED_KEYS',
163
+ message: 'Added quotes around unquoted object keys',
164
+ severity: 'warning',
165
+ });
166
+ }
167
+ return { text: result, issues };
168
+ }
169
+ /**
170
+ * Convert Python literal syntax to JSON
171
+ * e.g., True → true, False → false, None → null
172
+ */
173
+ function repairPythonLiterals(text) {
174
+ const issues = [];
175
+ let result = text;
176
+ let modified = false;
177
+ // Replace Python True with JSON true
178
+ if (/\bTrue\b/.test(result)) {
179
+ result = result.replace(/\bTrue\b/g, 'true');
180
+ modified = true;
181
+ }
182
+ // Replace Python False with JSON false
183
+ if (/\bFalse\b/.test(result)) {
184
+ result = result.replace(/\bFalse\b/g, 'false');
185
+ modified = true;
186
+ }
187
+ // Replace Python None with JSON null
188
+ if (/\bNone\b/.test(result)) {
189
+ result = result.replace(/\bNone\b/g, 'null');
190
+ modified = true;
191
+ }
192
+ if (modified) {
193
+ issues.push({
194
+ code: 'PYTHON_LITERALS',
195
+ message: 'Converted Python literals to JSON (True/False/None)',
196
+ severity: 'warning',
197
+ });
198
+ }
199
+ return { text: result, issues };
200
+ }
99
201
  /**
100
202
  * Check if text is valid JSON without throwing
101
203
  */
@@ -1 +1 @@
1
- {"version":3,"file":"repair.js","sourceRoot":"","sources":["../src/repair.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repair.js","sourceRoot":"","sources":["../src/repair.ts"],"names":[],"mappings":"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"}
package/dist/rescue.d.ts CHANGED
@@ -20,5 +20,24 @@ import { RescueResult, RescueOptions } from './types';
20
20
  * ```
21
21
  */
22
22
  export declare function rescueJson<T = unknown>(text: string, options?: RescueOptions): RescueResult<T> | RescueResult<T>[];
23
+ /**
24
+ * Convenience wrapper to get all JSON candidates
25
+ *
26
+ * @template T - The expected type of the parsed JSON
27
+ * @param text - The text containing JSON
28
+ * @param options - Configuration options (mode is always 'all')
29
+ * @returns An array of RescueResult
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * const results = rescueJsonAll<{ name: string }>(mixedText);
34
+ * results.forEach(result => {
35
+ * if (result.success) {
36
+ * console.log(result.data);
37
+ * }
38
+ * });
39
+ * ```
40
+ */
41
+ export declare function rescueJsonAll<T = unknown>(text: string, options?: Omit<RescueOptions, 'mode'>): RescueResult<T>[];
23
42
  export { RescueResult, RescueOptions, RepairIssue } from './types';
24
43
  //# sourceMappingURL=rescue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rescue.d.ts","sourceRoot":"","sources":["../src/rescue.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAe,MAAM,SAAS,CAAC;AAInE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,OAAO,EACpC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,CA2CrC;AA8DD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"rescue.d.ts","sourceRoot":"","sources":["../src/rescue.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAe,MAAM,SAAS,CAAC;AAInE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,CAAC,GAAG,OAAO,EACpC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,aAAkB,GAC1B,YAAY,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,CAqDrC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EACvC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAM,GACxC,YAAY,CAAC,CAAC,CAAC,EAAE,CAGnB;AA+FD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
package/dist/rescue.js CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.rescueJson = rescueJson;
7
+ exports.rescueJsonAll = rescueJsonAll;
7
8
  const extraction_1 = require("./extraction");
8
9
  const repair_1 = require("./repair");
9
10
  /**
@@ -40,6 +41,7 @@ function rescueJson(text, options = {}) {
40
41
  ],
41
42
  raw: '',
42
43
  repaired: '',
44
+ score: 0,
43
45
  };
44
46
  return mode === 'all' ? [emptyResult] : emptyResult;
45
47
  }
@@ -57,9 +59,39 @@ function rescueJson(text, options = {}) {
57
59
  if (mode === 'all') {
58
60
  return results;
59
61
  }
60
- // Return first successful or first result
62
+ if (mode === 'best') {
63
+ // Return the result with the highest score
64
+ return results.reduce((best, current) => {
65
+ const bestScore = best.score ?? 0;
66
+ const currentScore = current.score ?? 0;
67
+ return currentScore > bestScore ? current : best;
68
+ });
69
+ }
70
+ // Return first successful or first result (default 'first' mode)
61
71
  return results.find((r) => r.success) || results[0];
62
72
  }
73
+ /**
74
+ * Convenience wrapper to get all JSON candidates
75
+ *
76
+ * @template T - The expected type of the parsed JSON
77
+ * @param text - The text containing JSON
78
+ * @param options - Configuration options (mode is always 'all')
79
+ * @returns An array of RescueResult
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * const results = rescueJsonAll<{ name: string }>(mixedText);
84
+ * results.forEach(result => {
85
+ * if (result.success) {
86
+ * console.log(result.data);
87
+ * }
88
+ * });
89
+ * ```
90
+ */
91
+ function rescueJsonAll(text, options = {}) {
92
+ const results = rescueJson(text, { ...options, mode: 'all' });
93
+ return Array.isArray(results) ? results : [results];
94
+ }
63
95
  /**
64
96
  * Process a single candidate: attempt repair and parse
65
97
  */
@@ -68,12 +100,14 @@ function processCandidate(raw, shouldRepair) {
68
100
  let repaired = raw;
69
101
  // Try to parse as-is first
70
102
  if ((0, repair_1.isValidJson)(raw)) {
103
+ const score = calculateScore(raw, []);
71
104
  return {
72
105
  data: JSON.parse(raw),
73
106
  success: true,
74
107
  issues: [],
75
108
  raw,
76
109
  repaired: raw,
110
+ score,
77
111
  };
78
112
  }
79
113
  // If we should repair, apply repairs
@@ -83,12 +117,14 @@ function processCandidate(raw, shouldRepair) {
83
117
  allIssues.push(...repairResult.issues);
84
118
  // Try parsing after repair
85
119
  if ((0, repair_1.isValidJson)(repaired)) {
120
+ const score = calculateScore(repaired, allIssues);
86
121
  return {
87
122
  data: JSON.parse(repaired),
88
123
  success: true,
89
124
  issues: allIssues,
90
125
  raw,
91
126
  repaired,
127
+ score,
92
128
  };
93
129
  }
94
130
  }
@@ -113,6 +149,32 @@ function processCandidate(raw, shouldRepair) {
113
149
  ],
114
150
  raw,
115
151
  repaired,
152
+ score: 0,
116
153
  };
117
154
  }
155
+ /**
156
+ * Calculate a confidence score for the parsed result
157
+ * Score ranges from 0 to 1, where 1 is perfect (no repairs needed)
158
+ * and 0 is a parse failure
159
+ */
160
+ function calculateScore(text, issues) {
161
+ // Base score is 1.0 (perfect)
162
+ let score = 1.0;
163
+ // Penalize for each repair issue
164
+ // Warning issues reduce score by 0.05, error issues reduce by 0.1
165
+ for (const issue of issues) {
166
+ if (issue.severity === 'warning') {
167
+ score -= 0.05;
168
+ }
169
+ else {
170
+ score -= 0.1;
171
+ }
172
+ }
173
+ // Penalize for length (longer text might have more issues)
174
+ // But less significantly
175
+ const lengthPenalty = Math.log(text.length) / 1000;
176
+ score -= Math.min(lengthPenalty, 0.1);
177
+ // Ensure score stays in valid range
178
+ return Math.max(0, Math.min(1, score));
179
+ }
118
180
  //# sourceMappingURL=rescue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rescue.js","sourceRoot":"","sources":["../src/rescue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rescue.js","sourceRoot":"","sources":["../src/rescue.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -25,6 +25,8 @@ export interface RescueResult<T = unknown> {
25
25
  raw: string;
26
26
  /** The repaired text before parsing */
27
27
  repaired: string;
28
+ /** Score indicating likelihood this is correct JSON (0-1) */
29
+ score?: number;
28
30
  }
29
31
  /**
30
32
  * Extraction candidate found in the text
@@ -39,8 +41,8 @@ export interface ExtractionCandidate {
39
41
  * Options for rescueJson function
40
42
  */
41
43
  export interface RescueOptions {
42
- /** Mode of extraction: 'first' (default) or 'all' */
43
- mode?: 'first' | 'all';
44
+ /** Mode of extraction: 'first' (default), 'all', or 'best' (highest score) */
45
+ mode?: 'first' | 'all' | 'best';
44
46
  /** Whether to attempt auto-repair */
45
47
  autoRepair?: boolean;
46
48
  /** Custom repair rules */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,6BAA6B;IAC7B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,iBAAiB,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IACvB,qCAAqC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC,EAAE,CAAC;CAC/E"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,6BAA6B;IAC7B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,iBAAiB,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IAChC,qCAAqC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC,EAAE,CAAC;CAC/E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-rescue",
3
- "version": "0.2.2",
3
+ "version": "1.0.0",
4
4
  "description": "Rescue valid JSON from messy text by extracting candidates, applying safe repairs, and returning a parsed result with a transparent repair report.",
5
5
  "keywords": [
6
6
  "json",