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 +113 -0
- package/README.md +33 -31
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/repair.d.ts +16 -0
- package/dist/repair.d.ts.map +1 -1
- package/dist/repair.js +103 -1
- package/dist/repair.js.map +1 -1
- package/dist/rescue.d.ts +19 -0
- package/dist/rescue.d.ts.map +1 -1
- package/dist/rescue.js +63 -1
- package/dist/rescue.js.map +1 -1
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
|
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 (
|
|
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
|
|
25
|
-
- ✅ TypeScript generics support
|
|
26
|
-
- ✅ Multiple JSON extraction (`
|
|
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
|
-
-
|
|
29
|
-
-
|
|
30
|
-
- ⏳
|
|
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 | ✅
|
|
63
|
-
| 2 | Repair report with issue codes | ⭐⭐⭐ Highest | ✅
|
|
64
|
-
| 3 | Safe auto-repair for common defects | ⭐⭐ High | ✅
|
|
65
|
-
| 4 | Multiple JSON extraction (`all`) | ⭐⭐ High | ✅
|
|
66
|
-
| 5 | Candidate scoring
|
|
67
|
-
| 6 | Streaming/incremental parsing | ⭐ Medium | ⏳
|
|
68
|
-
| 7 | Field extraction API | ⭐ Low | ⏳
|
|
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
|
|
84
|
+
`json-rescue` is at **v1.0.0** - Production Ready. All core features are complete and stable.
|
|
83
85
|
|
|
84
|
-
### 3.1 Version Roadmap (
|
|
86
|
+
### 3.1 Version Roadmap (Completed)
|
|
85
87
|
|
|
86
88
|
```text
|
|
87
|
-
v0.1.0 (Core) → v0.2.
|
|
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 +
|
|
91
|
-
Report Expansion Scoring
|
|
92
|
+
Extract + Repair Multi + Stable Advanced
|
|
93
|
+
Report Expansion Scoring Contract Features
|
|
92
94
|
```
|
|
93
95
|
|
|
94
|
-
|
|
96
|
+
### 3.2 Feature Status by Version
|
|
95
97
|
|
|
96
98
|
| Version | Feature | Status |
|
|
97
99
|
|--------:|---------|:------|
|
|
98
|
-
| v0.1.0 | Markdown fence extraction | ✅
|
|
99
|
-
| v0.1.0 | Balanced brace extraction (string-aware) | ✅
|
|
100
|
-
| v0.1.0 | Repairs: trailing commas, JSONC comments, smart quotes | ✅
|
|
101
|
-
| v0.1.0 | Repair report (`issues[]`) | ✅
|
|
102
|
-
| v0.2.0 | Repairs: single quotes, unquoted keys, Python literals |
|
|
103
|
-
| v0.2.0 | Candidate scoring (mode: `'best'`) |
|
|
104
|
-
| v0.3.0 | `rescueJsonAll()` convenience |
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
| v1.
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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,
|
|
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
|
*/
|
package/dist/repair.d.ts.map
CHANGED
|
@@ -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,
|
|
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 = [
|
|
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
|
*/
|
package/dist/repair.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repair.js","sourceRoot":"","sources":["../src/repair.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAYH,
|
|
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
|
package/dist/rescue.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
package/dist/rescue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rescue.js","sourceRoot":"","sources":["../src/rescue.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAuBH,
|
|
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 '
|
|
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 */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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;
|
|
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