Find payloads by term id so they survive a .remove()

This commit is contained in:
dualfroz committed 2026-10-03 03:19:54 +02:00
1 parent 21ceba9e20
commit 2bef4a0319
2 files changed
+77 -30

No files matched your search

+54 -30
View File
@@ -1,5 +1,48 @@
import debug from './debug.js'
// payloads are stored by sentence index, which goes stale after a .remove()
// so find each one again by the ids of its first and last terms
const findPayloads = function (view) {
const db = view.world.model.one.db || {}
const where = new Map()
view.document.forEach((terms, n) => {
terms.forEach((term, i) => where.set(term.id, [n, i]))
})
const found = []
Object.keys(db).forEach(k => {
db[k].forEach(obj => {
const [, , , startId, endId] = obj.ptr
const start = where.get(startId)
const end = where.get(endId)
// its words were removed
if (!start || !end || start[0] !== end[0]) {
return
}
found.push({ k, obj, ptr: [start[0], start[1], end[1] + 1, startId, endId] })
})
})
return found
}
// all payloads inside our current matches
const getPayloads = function (view) {
const payloads = findPayloads(view)
const res = []
view.fullPointer.forEach(ptr => {
const seeking = view.update([ptr])
payloads.forEach(found => {
if (found.ptr[0] !== ptr[0]) {
return
}
const m = view.update([found.ptr])
if (seeking.has(m)) {
res.push({ ...found, match: m })
}
})
})
return res
}
export default {
//establish payload db
mutate: function (world) {
@@ -11,25 +54,12 @@ export default {
api: function (View) {
/** return any data on our given matches */
View.prototype.getPayloads = function () {
let res = []
const db = this.world.model.one.db || {}
this.fullPointer.forEach(ptr => {
const n = ptr[0]
if (Object.hasOwn(db, n)) {
// look at all vals for this sentence
const seeking = this.update([ptr])
db[n].forEach(obj => {
const m = this.update([obj.ptr])
if (seeking.has(m)) {
res = res.concat({
match: m,
val: obj.val,
})
}
})
return getPayloads(this).map(found => {
return {
match: found.match,
val: found.obj.val,
}
})
return res
}
/** add data about our current matches */
@@ -56,21 +86,15 @@ export default {
View.prototype.clearPayloads = function () {
const db = this.world.model.one.db || {}
// get each payload
const res = this.getPayloads()
res.forEach(obj => {
const ptr = obj.match.fullPointer[0] || []
const [n, start, end] = ptr
db[n] ||= []
getPayloads(this).forEach(({ k, obj }) => {
if (!Object.hasOwn(db, k)) {
return
}
// remove it from our list of payloads
db[n] = db[n].filter(r => {
if (r.ptr[1] === start && r.ptr[2] === end) {
return false
}
return true
})
db[k] = db[k].filter(r => r !== obj)
// clean-up any empty arrays
if (db[n].length === 0) {
delete db[n]
if (db[k].length === 0) {
delete db[k]
}
})
return this
+23
View File
@@ -57,3 +57,26 @@ test('payload-fn', function (t) {
t.equal(doc.getPayloads().length, 5, '5-now')
t.end()
})
test('payload-after-remove', function (t) {
let doc = nlp('one apple. two pears. three plums.')
doc.match('(apple|plums)').addPayload(m => ({ fruit: m.text('normal') }))
t.equal(doc.getPayloads().length, 2, 'before-remove')
doc.remove('two pears')
let fruit = doc.getPayloads().map(p => p.val.fruit)
t.deepEqual(fruit, ['apple', 'plums'], 'after-remove')
t.equal(doc.match('plums').getPayloads().length, 1, 'plums-still-found')
doc.match('plums').clearPayloads()
fruit = doc.getPayloads().map(p => p.val.fruit)
t.deepEqual(fruit, ['apple'], 'clear-after-remove')
// removing the payload's own words drops it
doc = nlp('one apple. two pears. three plums.')
doc.match('(apple|pears|plums)').addPayload(m => ({ fruit: m.text('normal') }))
doc.remove('two pears')
fruit = doc.getPayloads().map(p => p.val.fruit)
t.deepEqual(fruit, ['apple', 'plums'], 'removed-payload-is-gone')
t.end()
})