Skip to content

Commit b95e17f

Browse files
committed
fix(pattern-extractor): ensure extracted values are strings and handle undefined keys
1 parent 5f34d25 commit b95e17f

File tree

3 files changed

+78
-11
lines changed

3 files changed

+78
-11
lines changed

entrypoints/content/components/GmailTools/GmailComposeCard.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,11 +484,11 @@ const start = async () => {
484484
// Fallback: try to extract from raw text if structured extraction failed
485485
if (!optimizedSubject.value) {
486486
const extractSubjectMatch = extractValueOfKeyByPattern(text, 'subject')
487-
if (extractSubjectMatch) optimizedSubject.value = extractSubjectMatch
487+
if (extractSubjectMatch && typeof extractSubjectMatch === 'string') optimizedSubject.value = extractSubjectMatch
488488
}
489489
if (!optimizedBody.value) {
490490
const extractBodyMatch = extractValueOfKeyByPattern(text, 'body')
491-
if (extractBodyMatch) optimizedBody.value = extractBodyMatch
491+
if (extractBodyMatch && typeof extractBodyMatch === 'string') optimizedBody.value = extractBodyMatch
492492
}
493493
494494
logger.debug('Gmail compose structured response:', {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { describe, expect, it } from 'vitest'
2+
3+
import { extractValueOfKeyByPattern } from './pattern-extractor'
4+
5+
describe('json key-value pattern extractor', () => {
6+
it('should extract values correctly', async () => {
7+
const testString = JSON.stringify({
8+
a: 'this is a test string with a "quote" and a newline\ncharacter',
9+
b: 123,
10+
c: true,
11+
d: null,
12+
e: false,
13+
})
14+
const a = extractValueOfKeyByPattern(testString, 'a')
15+
expect(a).toBe('this is a test string with a "quote" and a newline\ncharacter')
16+
const b = extractValueOfKeyByPattern(testString, 'b')
17+
expect(b).toBe(123)
18+
const c = extractValueOfKeyByPattern(testString, 'c')
19+
expect(c).toBe(true)
20+
const d = extractValueOfKeyByPattern(testString, 'd')
21+
expect(d).toBe(null)
22+
const e = extractValueOfKeyByPattern(testString, 'e')
23+
expect(e).toBe(false)
24+
const undefinedKey = extractValueOfKeyByPattern(testString, 'undefinedKey')
25+
expect(undefinedKey).toBe(undefined)
26+
})
27+
28+
it('should extract values correctly for pretty-printed JSON', async () => {
29+
const testString = JSON.stringify({
30+
a: 'this is a test string with a "quote" and a newline\ncharacter',
31+
b: 123,
32+
c: true,
33+
d: null,
34+
e: false,
35+
f: {
36+
nested: 'value',
37+
},
38+
}, null, 2)
39+
const a = extractValueOfKeyByPattern(testString, 'a')
40+
expect(a).toBe('this is a test string with a "quote" and a newline\ncharacter')
41+
const b = extractValueOfKeyByPattern(testString, 'b')
42+
expect(b).toBe(123)
43+
const c = extractValueOfKeyByPattern(testString, 'c')
44+
expect(c).toBe(true)
45+
const d = extractValueOfKeyByPattern(testString, 'd')
46+
expect(d).toBe(null)
47+
const e = extractValueOfKeyByPattern(testString, 'e')
48+
expect(e).toBe(false)
49+
const f = extractValueOfKeyByPattern(testString, 'f')
50+
expect(f).toEqual(undefined)
51+
const nested = extractValueOfKeyByPattern(testString, 'nested')
52+
expect(nested).toBe('value')
53+
})
54+
})
Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
1-
export function extractValueOfKeyByPattern(json: string, key: string): string | null {
2-
const regex = new RegExp(`"${key}"\\s*:\\s*("(.*?)"|\\d+|true|false|null)`, 'is')
1+
export function extractRawValueOfKeyByPattern(json: string, key: string): string | undefined {
2+
const regex = new RegExp(`"${key}"\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|\\d+|true|false|null)`, 'is')
33

44
const match = json.match(regex)
55
if (match && match[1]) {
6-
let value = match[1].trim()
7-
if (value.startsWith('"') && value.endsWith('"')) {
8-
value = value.slice(1, -1)
9-
const unescapedValue = value.replace(/\\"/g, '"').replace(/\\\\/g, '\\').replace(/\\n/g, '\n')
10-
return unescapedValue
11-
}
6+
const value = match[1].trim()
127
return value
138
}
14-
return null
9+
return undefined
10+
}
11+
12+
type JSONValue = string | number | boolean | null
13+
14+
export function extractValueOfKeyByPattern(json: string, key: string): JSONValue | undefined {
15+
const rawValue = extractRawValueOfKeyByPattern(json, key)
16+
if (rawValue === null) return null
17+
18+
if (rawValue === 'true') return true
19+
if (rawValue === 'false') return false
20+
if (rawValue === 'null') return null
21+
if (!isNaN(Number(rawValue))) return Number(rawValue)
22+
if (rawValue && rawValue.startsWith('"') && rawValue.endsWith('"')) {
23+
const value = rawValue.slice(1, -1)
24+
const unescapedValue = value.replace(/\\"/g, '"').replace(/\\n/g, '\n').replace(/\\\\/g, '\\')
25+
return unescapedValue
26+
}
27+
return undefined
1528
}

0 commit comments

Comments
 (0)