Skip to content

Commit f9bfda4

Browse files
shakyShanegithub-actions[bot]
authored andcommitted
Release build 5.3.0 [ci release]
1 parent 59752eb commit f9bfda4

File tree

11 files changed

+276
-89
lines changed

11 files changed

+276
-89
lines changed

Sources/ContentScopeScripts/dist/contentScope.js

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

Sources/ContentScopeScripts/dist/contentScopeIsolated.js

Lines changed: 32 additions & 17 deletions
Large diffs are not rendered by default.

build/android/contentScope.js

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

build/contentScope.js

Lines changed: 32 additions & 17 deletions
Large diffs are not rendered by default.

build/integration/contentScope.js

Lines changed: 32 additions & 17 deletions
Large diffs are not rendered by default.

build/tracker-lookup.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

build/windows/contentScope.js

Lines changed: 32 additions & 17 deletions
Large diffs are not rendered by default.

src/features/broker-protection/actions/extract.js

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { getElement, getElementMatches, getElements } from '../utils.js' // Assuming you have imported the address comparison function
1+
import {
2+
cleanArray,
3+
getElement,
4+
getElementMatches,
5+
getElements
6+
} from '../utils.js' // Assuming you have imported the address comparison function
27
import { ErrorResponse, ProfileResult, SuccessResponse } from '../types.js'
38
import { isSameAge } from '../comparisons/is-same-age.js'
49
import { isSameName } from '../comparisons/is-same-name.js'
@@ -72,7 +77,12 @@ export function extractProfiles (action, userData, root = document) {
7277

7378
return {
7479
results: profilesElementList.map((element) => {
75-
const scrapedData = createProfile(element, action.profile)
80+
const elementFactory = (key, value) => {
81+
return value?.findElements
82+
? cleanArray(getElements(element, value.selector))
83+
: cleanArray(getElement(element, value.selector) || getElementMatches(element, value.selector))
84+
}
85+
const scrapedData = createProfile(elementFactory, action.profile)
7686
const { result, score, matchedFields } = scrapedDataMatchesUserData(userData, scrapedData)
7787
return new ProfileResult({
7888
scrapedData,
@@ -105,37 +115,40 @@ export function extractProfiles (action, userData, root = document) {
105115
* "profileUrl": "https://example.com/1234"
106116
* }
107117
*
108-
* @param {HTMLElement} profileElement
118+
* @param {(key: string, value: ExtractProfileProperty) => {innerText: string}[]} elementFactory
119+
* a function that produces elements for a given key + ExtractProfileProperty
109120
* @param {Record<string, ExtractProfileProperty>} extractData
110121
* @return {Record<string, any>}
111122
*/
112-
function createProfile (profileElement, extractData) {
123+
export function createProfile (elementFactory, extractData) {
113124
const output = {}
114125
for (const [key, value] of Object.entries(extractData)) {
115126
if (!value?.selector) {
116127
output[key] = null
117128
} else {
129+
const elements = elementFactory(key, value)
118130
const evaluatedValue = value?.findElements
119-
? findFromElements(profileElement, key, value)
120-
: findFromElement(profileElement, key, value)
131+
? findFromElements(elements, key, value)
132+
: findFromElement(elements[0], key, value)
121133

122134
// Note: This can return a string, string[], or null
123135
const extractedValue = extractValue(key, value, evaluatedValue)
124136

125-
// try to use the extracted value first, then the originally evaluated, falling back to null
126-
output[key] = extractedValue || evaluatedValue || null
137+
// try to use the extracted value, or fall back to null
138+
// this allows 'extractValue' to return null|undefined
139+
output[key] = extractedValue || null
127140
}
128141
}
129142
return output
130143
}
131144

132145
/**
133-
* @param {HTMLElement} profileElement
146+
* @param {{innerText: string}[]} elements
134147
* @param {string} key
135148
* @param {ExtractProfileProperty} extractField
149+
* @return {string[]}
136150
*/
137-
function findFromElements (profileElement, key, extractField) {
138-
const elements = getElements(profileElement, extractField.selector) || null
151+
function findFromElements (elements, key, extractField) {
139152
const elementValues = []
140153
if (elements) {
141154
for (const element of elements) {
@@ -153,15 +166,12 @@ function findFromElements (profileElement, key, extractField) {
153166
}
154167

155168
/**
156-
* @param {HTMLElement} profileElement
169+
* @param {{innerText: string}} element
157170
* @param {string} dataKey - such as 'name', 'age' etc
158171
* @param {ExtractProfileProperty} extractField
159172
* @return {string}
160173
*/
161-
function findFromElement (profileElement, dataKey, extractField) {
162-
const element = getElement(profileElement, extractField.selector) ||
163-
getElementMatches(profileElement, extractField.selector)
164-
174+
function findFromElement (element, dataKey, extractField) {
165175
// todo: should we use textContent here?
166176
let elementValue = rules[dataKey]?.(element) ?? element?.innerText ?? null
167177

@@ -282,7 +292,7 @@ export function aggregateFields (profile) {
282292
* @param {string} key
283293
* @param {ExtractProfileProperty} value
284294
* @param {string | string[]} elementValue
285-
* @return {string|string[]|null}
295+
* @return {string|string[]|null|undefined}
286296
*/
287297
export function extractValue (key, value, elementValue) {
288298
if (!elementValue) return null

src/features/broker-protection/utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,13 @@ function safeQuerySelectorAllXpath (element, selector) {
161161
export function generateRandomInt (min, max) {
162162
return Math.floor(Math.random() * (max - min + 1) + min)
163163
}
164+
165+
/**
166+
* Flatten create an array of any input, removing nulls, undefined and empty strings
167+
* @template T
168+
* @param {T | T[] | null | undefined} input
169+
* @return {NonNullable<T>[]}
170+
*/
171+
export function cleanArray (input) {
172+
return [].concat(/** @type {any} */(input)).flat().filter(Boolean)
173+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { createProfile } from '../src/features/broker-protection/actions/extract.js'
2+
3+
describe('create profiles from extracted data', () => {
4+
it('handles combined, single strings', () => {
5+
const selectors = {
6+
name: {
7+
selector: '.name',
8+
beforeText: ','
9+
},
10+
age: {
11+
selector: '.name',
12+
afterText: ','
13+
}
14+
}
15+
16+
const elementExamples = [
17+
{ text: 'John smith, 39', expected: { name: 'John smith', age: '39' } },
18+
{ text: 'John smith , 39', expected: { name: 'John smith', age: '39' } },
19+
{ text: 'John\nsmith , 39', expected: { name: 'John smith', age: '39' } },
20+
{ text: 'John\nsmith , 39 anything', expected: { name: 'John smith', age: '39' } },
21+
{ text: ' John smith, 39', expected: { name: 'John smith', age: '39' } },
22+
{ text: ' John smith,39', expected: { name: 'John smith', age: '39' } },
23+
{ text: ' John smith, ~39', expected: { name: 'John smith', age: '39' } },
24+
{ text: 'Jane Doe, 45', expected: { name: 'Jane Doe', age: '45' } },
25+
{ text: ' Robert Johnson,22', expected: { name: 'Robert Johnson', age: '22' } },
26+
{ text: 'Emily Wilson , 29 ', expected: { name: 'Emily Wilson', age: '29' } },
27+
{ text: 'Daniel Miller\n\n, 56', expected: { name: 'Daniel Miller', age: '56' } },
28+
{ text: 'Henry White ,46', expected: { name: 'Henry White', age: '46' } },
29+
{ text: 'Linda Brown ~ , 35', expected: { name: 'Linda Brown ~', age: '35' } },
30+
{ text: 'Emma Green, 30 any', expected: { name: 'Emma Green', age: '30' } },
31+
{ text: ' Sophia Blue, 26', expected: { name: 'Sophia Blue', age: '26' } },
32+
33+
// examples where age is absent, so the result should be null
34+
{ text: 'John smith', expected: { name: 'John smith', age: null } },
35+
{ text: 'John smith , ', expected: { name: 'John smith', age: null } },
36+
{ text: 'John smith \n,\n ', expected: { name: 'John smith', age: null } }
37+
]
38+
39+
for (const elementExample of elementExamples) {
40+
const elementFactory = () => {
41+
return [{ innerText: elementExample.text }]
42+
}
43+
const profile = createProfile(elementFactory, selectors)
44+
expect(profile).toEqual(elementExample.expected)
45+
}
46+
})
47+
it('handles multiple strings', () => {
48+
const elementExamples = [
49+
{
50+
selectors: {
51+
alternativeNamesList: {
52+
selector: 'example',
53+
afterText: 'Also Known as:',
54+
separator: ','
55+
}
56+
},
57+
elements: [{ innerText: 'Also Known as: John Smith, Jon Smith' }],
58+
expected: {
59+
alternativeNamesList: ['John Smith', 'Jon Smith']
60+
}
61+
},
62+
{
63+
selectors: {
64+
alternativeNamesList: {
65+
selector: 'example',
66+
findElements: true,
67+
afterText: 'Also Known as:'
68+
}
69+
},
70+
elements: [
71+
{ innerText: 'Also Known as: John Smith' },
72+
{ innerText: 'Jon Smith' }
73+
],
74+
expected: {
75+
alternativeNamesList: ['John Smith', 'Jon Smith']
76+
}
77+
},
78+
{
79+
selectors: {
80+
alternativeNamesList: {
81+
selector: 'example',
82+
findElements: true,
83+
beforeText: ', '
84+
}
85+
},
86+
elements: [
87+
{ innerText: 'John Smith, 89' },
88+
{ innerText: 'Jon Smith, 78' }
89+
],
90+
expected: {
91+
alternativeNamesList: ['John Smith', 'Jon Smith']
92+
}
93+
}
94+
]
95+
96+
for (const elementExample of elementExamples) {
97+
const elementFactory = () => elementExample.elements
98+
const profile = createProfile(elementFactory, elementExample.selectors)
99+
expect(profile).toEqual(elementExample.expected)
100+
}
101+
})
102+
})

0 commit comments

Comments
 (0)