@atproto/api
Advanced tools
Comparing version 0.13.14 to 0.13.15
# @atproto/api | ||
## 0.13.15 | ||
### Patch Changes | ||
- [#2661](https://github.com/bluesky-social/atproto/pull/2661) [`d6f33b474`](https://github.com/bluesky-social/atproto/commit/d6f33b4742e0b94722a993efc7d18833d9416bb6) Thanks [@foysalit](https://github.com/foysalit)! - Add mod events and status filter for account and record hosting status | ||
- [#2957](https://github.com/bluesky-social/atproto/pull/2957) [`b6eeb81c6`](https://github.com/bluesky-social/atproto/commit/b6eeb81c6d454b5ae91b05a21fc1820274c1b429) Thanks [@gaearon](https://github.com/gaearon)! - Detect facets in parallel | ||
- [#2917](https://github.com/bluesky-social/atproto/pull/2917) [`839202a3d`](https://github.com/bluesky-social/atproto/commit/839202a3d2b01de25de900cec7540019545798c6) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Allow instantiating an API Agent with a string or URL | ||
- [#2933](https://github.com/bluesky-social/atproto/pull/2933) [`e680d55ca`](https://github.com/bluesky-social/atproto/commit/e680d55ca2d7f6b213e2a8693eba6be39163ba41) Thanks [@mozzius](https://github.com/mozzius)! - Fix handling of invalid facets in RichText | ||
- [#2905](https://github.com/bluesky-social/atproto/pull/2905) [`c4b5e5395`](https://github.com/bluesky-social/atproto/commit/c4b5e53957463c37dd16fdd1b897d4ab02ab8e84) Thanks [@foysalit](https://github.com/foysalit)! - Add user specific and instance-wide settings api for ozone | ||
## 0.13.14 | ||
@@ -4,0 +18,0 @@ |
@@ -25,3 +25,2 @@ import { FetchHandler, XrpcClient } from '@atproto/xrpc'; | ||
#private; | ||
readonly sessionManager: SessionManager; | ||
/** | ||
@@ -41,3 +40,4 @@ * The labelers to be used across all requests with the takedown capability | ||
get xrpc(): XrpcClient; | ||
constructor(sessionManager: SessionManager); | ||
readonly sessionManager: SessionManager; | ||
constructor(options: string | URL | SessionManager); | ||
clone(): Agent; | ||
@@ -44,0 +44,0 @@ copyInto<T extends Agent>(inst: T): T; |
@@ -56,4 +56,9 @@ "use strict"; | ||
} | ||
constructor(sessionManager) { | ||
const fetchHandler = (0, xrpc_1.buildFetchHandler)(sessionManager); | ||
constructor(options) { | ||
const sessionManager = typeof options === 'string' || options instanceof URL | ||
? { | ||
did: undefined, | ||
fetchHandler: (0, xrpc_1.buildFetchHandler)(options), | ||
} | ||
: options; | ||
super((url, init) => { | ||
@@ -73,10 +78,4 @@ const headers = new Headers(init?.headers); | ||
.join(', ')); | ||
return fetchHandler(url, { ...init, headers }); | ||
return this.sessionManager.fetchHandler(url, { ...init, headers }); | ||
}, lexicons_1.schemas); | ||
Object.defineProperty(this, "sessionManager", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: sessionManager | ||
}); | ||
//#endregion | ||
@@ -107,2 +106,8 @@ Object.defineProperty(this, "com", { | ||
}); | ||
Object.defineProperty(this, "sessionManager", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "labelers", { | ||
@@ -280,2 +285,3 @@ enumerable: true, | ||
); | ||
this.sessionManager = sessionManager; | ||
} | ||
@@ -282,0 +288,0 @@ //#region Cloning utilities |
@@ -13,3 +13,3 @@ /** | ||
id: number; | ||
event: ModEventTakedown | ModEventReverseTakedown | ModEventComment | ModEventReport | ModEventLabel | ModEventAcknowledge | ModEventEscalate | ModEventMute | ModEventUnmute | ModEventMuteReporter | ModEventUnmuteReporter | ModEventEmail | ModEventResolveAppeal | ModEventDivert | ModEventTag | { | ||
event: ModEventTakedown | ModEventReverseTakedown | ModEventComment | ModEventReport | ModEventLabel | ModEventAcknowledge | ModEventEscalate | ModEventMute | ModEventUnmute | ModEventMuteReporter | ModEventUnmuteReporter | ModEventEmail | ModEventResolveAppeal | ModEventDivert | ModEventTag | AccountEvent | IdentityEvent | RecordEvent | { | ||
$type: string; | ||
@@ -33,3 +33,3 @@ [k: string]: unknown; | ||
id: number; | ||
event: ModEventTakedown | ModEventReverseTakedown | ModEventComment | ModEventReport | ModEventLabel | ModEventAcknowledge | ModEventEscalate | ModEventMute | ModEventUnmute | ModEventMuteReporter | ModEventUnmuteReporter | ModEventEmail | ModEventResolveAppeal | ModEventDivert | ModEventTag | { | ||
event: ModEventTakedown | ModEventReverseTakedown | ModEventComment | ModEventReport | ModEventLabel | ModEventAcknowledge | ModEventEscalate | ModEventMute | ModEventUnmute | ModEventMuteReporter | ModEventUnmuteReporter | ModEventEmail | ModEventResolveAppeal | ModEventDivert | ModEventTag | AccountEvent | IdentityEvent | RecordEvent | { | ||
$type: string; | ||
@@ -55,2 +55,6 @@ [k: string]: unknown; | ||
}; | ||
hosting?: AccountHosting | RecordHosting | { | ||
$type: string; | ||
[k: string]: unknown; | ||
}; | ||
subjectBlobCids?: string[]; | ||
@@ -222,2 +226,34 @@ subjectRepoHandle?: string; | ||
export declare function validateModEventTag(v: unknown): ValidationResult; | ||
/** Logs account status related events on a repo subject. Normally captured by automod from the firehose and emitted to ozone for historical tracking. */ | ||
export interface AccountEvent { | ||
comment?: string; | ||
/** Indicates that the account has a repository which can be fetched from the host that emitted this event. */ | ||
active: boolean; | ||
status?: 'unknown' | 'deactivated' | 'deleted' | 'takendown' | 'suspended' | 'tombstoned' | (string & {}); | ||
timestamp: string; | ||
[k: string]: unknown; | ||
} | ||
export declare function isAccountEvent(v: unknown): v is AccountEvent; | ||
export declare function validateAccountEvent(v: unknown): ValidationResult; | ||
/** Logs identity related events on a repo subject. Normally captured by automod from the firehose and emitted to ozone for historical tracking. */ | ||
export interface IdentityEvent { | ||
comment?: string; | ||
handle?: string; | ||
pdsHost?: string; | ||
tombstone?: boolean; | ||
timestamp: string; | ||
[k: string]: unknown; | ||
} | ||
export declare function isIdentityEvent(v: unknown): v is IdentityEvent; | ||
export declare function validateIdentityEvent(v: unknown): ValidationResult; | ||
/** Logs lifecycle event on a record subject. Normally captured by automod from the firehose and emitted to ozone for historical tracking. */ | ||
export interface RecordEvent { | ||
comment?: string; | ||
op: 'create' | 'update' | 'delete' | (string & {}); | ||
cid?: string; | ||
timestamp: string; | ||
[k: string]: unknown; | ||
} | ||
export declare function isRecordEvent(v: unknown): v is RecordEvent; | ||
export declare function validateRecordEvent(v: unknown): ValidationResult; | ||
export interface RepoView { | ||
@@ -336,2 +372,22 @@ did: string; | ||
export declare function validateVideoDetails(v: unknown): ValidationResult; | ||
export interface AccountHosting { | ||
status: 'takendown' | 'suspended' | 'deleted' | 'deactivated' | 'unknown' | (string & {}); | ||
updatedAt?: string; | ||
createdAt?: string; | ||
deletedAt?: string; | ||
deactivatedAt?: string; | ||
reactivatedAt?: string; | ||
[k: string]: unknown; | ||
} | ||
export declare function isAccountHosting(v: unknown): v is AccountHosting; | ||
export declare function validateAccountHosting(v: unknown): ValidationResult; | ||
export interface RecordHosting { | ||
status: 'deleted' | 'unknown' | (string & {}); | ||
updatedAt?: string; | ||
createdAt?: string; | ||
deletedAt?: string; | ||
[k: string]: unknown; | ||
} | ||
export declare function isRecordHosting(v: unknown): v is RecordHosting; | ||
export declare function validateRecordHosting(v: unknown): ValidationResult; | ||
//# sourceMappingURL=defs.d.ts.map |
@@ -40,2 +40,8 @@ "use strict"; | ||
exports.validateModEventTag = validateModEventTag; | ||
exports.isAccountEvent = isAccountEvent; | ||
exports.validateAccountEvent = validateAccountEvent; | ||
exports.isIdentityEvent = isIdentityEvent; | ||
exports.validateIdentityEvent = validateIdentityEvent; | ||
exports.isRecordEvent = isRecordEvent; | ||
exports.validateRecordEvent = validateRecordEvent; | ||
exports.isRepoView = isRepoView; | ||
@@ -63,2 +69,6 @@ exports.validateRepoView = validateRepoView; | ||
exports.validateVideoDetails = validateVideoDetails; | ||
exports.isAccountHosting = isAccountHosting; | ||
exports.validateAccountHosting = validateAccountHosting; | ||
exports.isRecordHosting = isRecordHosting; | ||
exports.validateRecordHosting = validateRecordHosting; | ||
const util_1 = require("../../../../util"); | ||
@@ -218,2 +228,26 @@ const lexicons_1 = require("../../../../lexicons"); | ||
} | ||
function isAccountEvent(v) { | ||
return ((0, util_1.isObj)(v) && | ||
(0, util_1.hasProp)(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#accountEvent'); | ||
} | ||
function validateAccountEvent(v) { | ||
return lexicons_1.lexicons.validate('tools.ozone.moderation.defs#accountEvent', v); | ||
} | ||
function isIdentityEvent(v) { | ||
return ((0, util_1.isObj)(v) && | ||
(0, util_1.hasProp)(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#identityEvent'); | ||
} | ||
function validateIdentityEvent(v) { | ||
return lexicons_1.lexicons.validate('tools.ozone.moderation.defs#identityEvent', v); | ||
} | ||
function isRecordEvent(v) { | ||
return ((0, util_1.isObj)(v) && | ||
(0, util_1.hasProp)(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#recordEvent'); | ||
} | ||
function validateRecordEvent(v) { | ||
return lexicons_1.lexicons.validate('tools.ozone.moderation.defs#recordEvent', v); | ||
} | ||
function isRepoView(v) { | ||
@@ -307,2 +341,18 @@ return ((0, util_1.isObj)(v) && | ||
} | ||
function isAccountHosting(v) { | ||
return ((0, util_1.isObj)(v) && | ||
(0, util_1.hasProp)(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#accountHosting'); | ||
} | ||
function validateAccountHosting(v) { | ||
return lexicons_1.lexicons.validate('tools.ozone.moderation.defs#accountHosting', v); | ||
} | ||
function isRecordHosting(v) { | ||
return ((0, util_1.isObj)(v) && | ||
(0, util_1.hasProp)(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#recordHosting'); | ||
} | ||
function validateRecordHosting(v) { | ||
return lexicons_1.lexicons.validate('tools.ozone.moderation.defs#recordHosting', v); | ||
} | ||
//# sourceMappingURL=defs.js.map |
@@ -11,3 +11,3 @@ /** | ||
export interface InputSchema { | ||
event: ToolsOzoneModerationDefs.ModEventTakedown | ToolsOzoneModerationDefs.ModEventAcknowledge | ToolsOzoneModerationDefs.ModEventEscalate | ToolsOzoneModerationDefs.ModEventComment | ToolsOzoneModerationDefs.ModEventLabel | ToolsOzoneModerationDefs.ModEventReport | ToolsOzoneModerationDefs.ModEventMute | ToolsOzoneModerationDefs.ModEventUnmute | ToolsOzoneModerationDefs.ModEventMuteReporter | ToolsOzoneModerationDefs.ModEventUnmuteReporter | ToolsOzoneModerationDefs.ModEventReverseTakedown | ToolsOzoneModerationDefs.ModEventResolveAppeal | ToolsOzoneModerationDefs.ModEventEmail | ToolsOzoneModerationDefs.ModEventTag | { | ||
event: ToolsOzoneModerationDefs.ModEventTakedown | ToolsOzoneModerationDefs.ModEventAcknowledge | ToolsOzoneModerationDefs.ModEventEscalate | ToolsOzoneModerationDefs.ModEventComment | ToolsOzoneModerationDefs.ModEventLabel | ToolsOzoneModerationDefs.ModEventReport | ToolsOzoneModerationDefs.ModEventMute | ToolsOzoneModerationDefs.ModEventUnmute | ToolsOzoneModerationDefs.ModEventMuteReporter | ToolsOzoneModerationDefs.ModEventUnmuteReporter | ToolsOzoneModerationDefs.ModEventReverseTakedown | ToolsOzoneModerationDefs.ModEventResolveAppeal | ToolsOzoneModerationDefs.ModEventEmail | ToolsOzoneModerationDefs.ModEventTag | ToolsOzoneModerationDefs.AccountEvent | ToolsOzoneModerationDefs.IdentityEvent | ToolsOzoneModerationDefs.RecordEvent | { | ||
$type: string; | ||
@@ -14,0 +14,0 @@ [k: string]: unknown; |
@@ -19,2 +19,12 @@ /** | ||
reviewedAfter?: string; | ||
/** Search subjects where the associated record/account was deleted after a given timestamp */ | ||
hostingDeletedAfter?: string; | ||
/** Search subjects where the associated record/account was deleted before a given timestamp */ | ||
hostingDeletedBefore?: string; | ||
/** Search subjects where the associated record/account was updated after a given timestamp */ | ||
hostingUpdatedAfter?: string; | ||
/** Search subjects where the associated record/account was updated before a given timestamp */ | ||
hostingUpdatedBefore?: string; | ||
/** Search subjects by the status of the associated record/account */ | ||
hostingStatuses?: string[]; | ||
/** Search subjects reviewed before a given timestamp */ | ||
@@ -21,0 +31,0 @@ reviewedBefore?: string; |
@@ -167,3 +167,3 @@ "use strict"; | ||
if (this.facets) { | ||
this.facets.sort(facetSort); | ||
this.facets = this.facets.filter(facetFilter).sort(facetSort); | ||
} | ||
@@ -313,13 +313,17 @@ if (opts?.cleanNewlines) { | ||
if (this.facets) { | ||
const promises = []; | ||
for (const facet of this.facets) { | ||
for (const feature of facet.features) { | ||
if (client_1.AppBskyRichtextFacet.isMention(feature)) { | ||
const did = await agent.com.atproto.identity | ||
promises.push(agent.com.atproto.identity | ||
.resolveHandle({ handle: feature.did }) | ||
.then((res) => res?.data.did) | ||
.catch((_) => undefined) | ||
.then((res) => res?.data.did); | ||
feature.did = did || ''; | ||
.then((did) => { | ||
feature.did = did || ''; | ||
})); | ||
} | ||
} | ||
} | ||
await Promise.allSettled(promises); | ||
this.facets.sort(facetSort); | ||
@@ -342,2 +346,5 @@ } | ||
const facetSort = (a, b) => a.index.byteStart - b.index.byteStart; | ||
const facetFilter = (facet) => | ||
// discard negative-length facets. zero-length facets are valid | ||
facet.index.byteStart <= facet.index.byteEnd; | ||
function entitiesToFacets(text, entities) { | ||
@@ -344,0 +351,0 @@ const facets = []; |
{ | ||
"name": "@atproto/api", | ||
"version": "0.13.14", | ||
"version": "0.13.15", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "description": "Client library for atproto and Bluesky", |
import { TID } from '@atproto/common-web' | ||
import { AtUri, ensureValidDid } from '@atproto/syntax' | ||
import { buildFetchHandler, FetchHandler, XrpcClient } from '@atproto/xrpc' | ||
import { | ||
buildFetchHandler, | ||
BuildFetchHandlerOptions, | ||
FetchHandler, | ||
XrpcClient, | ||
} from '@atproto/xrpc' | ||
import AwaitLock from 'await-lock' | ||
@@ -108,5 +113,13 @@ import { | ||
constructor(readonly sessionManager: SessionManager) { | ||
const fetchHandler = buildFetchHandler(sessionManager) | ||
readonly sessionManager: SessionManager | ||
constructor(options: string | URL | SessionManager) { | ||
const sessionManager: SessionManager = | ||
typeof options === 'string' || options instanceof URL | ||
? { | ||
did: undefined, | ||
fetchHandler: buildFetchHandler(options), | ||
} | ||
: options | ||
super((url, init) => { | ||
@@ -132,4 +145,6 @@ const headers = new Headers(init?.headers) | ||
return fetchHandler(url, { ...init, headers }) | ||
return this.sessionManager.fetchHandler(url, { ...init, headers }) | ||
}, schemas) | ||
this.sessionManager = sessionManager | ||
} | ||
@@ -136,0 +151,0 @@ |
@@ -33,2 +33,5 @@ /** | ||
| ModEventTag | ||
| AccountEvent | ||
| IdentityEvent | ||
| RecordEvent | ||
| { $type: string; [k: string]: unknown } | ||
@@ -78,2 +81,5 @@ subject: | ||
| ModEventTag | ||
| AccountEvent | ||
| IdentityEvent | ||
| RecordEvent | ||
| { $type: string; [k: string]: unknown } | ||
@@ -110,2 +116,6 @@ subject: | ||
| { $type: string; [k: string]: unknown } | ||
hosting?: | ||
| AccountHosting | ||
| RecordHosting | ||
| { $type: string; [k: string]: unknown } | ||
subjectBlobCids?: string[] | ||
@@ -478,2 +488,74 @@ subjectRepoHandle?: string | ||
/** Logs account status related events on a repo subject. Normally captured by automod from the firehose and emitted to ozone for historical tracking. */ | ||
export interface AccountEvent { | ||
comment?: string | ||
/** Indicates that the account has a repository which can be fetched from the host that emitted this event. */ | ||
active: boolean | ||
status?: | ||
| 'unknown' | ||
| 'deactivated' | ||
| 'deleted' | ||
| 'takendown' | ||
| 'suspended' | ||
| 'tombstoned' | ||
| (string & {}) | ||
timestamp: string | ||
[k: string]: unknown | ||
} | ||
export function isAccountEvent(v: unknown): v is AccountEvent { | ||
return ( | ||
isObj(v) && | ||
hasProp(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#accountEvent' | ||
) | ||
} | ||
export function validateAccountEvent(v: unknown): ValidationResult { | ||
return lexicons.validate('tools.ozone.moderation.defs#accountEvent', v) | ||
} | ||
/** Logs identity related events on a repo subject. Normally captured by automod from the firehose and emitted to ozone for historical tracking. */ | ||
export interface IdentityEvent { | ||
comment?: string | ||
handle?: string | ||
pdsHost?: string | ||
tombstone?: boolean | ||
timestamp: string | ||
[k: string]: unknown | ||
} | ||
export function isIdentityEvent(v: unknown): v is IdentityEvent { | ||
return ( | ||
isObj(v) && | ||
hasProp(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#identityEvent' | ||
) | ||
} | ||
export function validateIdentityEvent(v: unknown): ValidationResult { | ||
return lexicons.validate('tools.ozone.moderation.defs#identityEvent', v) | ||
} | ||
/** Logs lifecycle event on a record subject. Normally captured by automod from the firehose and emitted to ozone for historical tracking. */ | ||
export interface RecordEvent { | ||
comment?: string | ||
op: 'create' | 'update' | 'delete' | (string & {}) | ||
cid?: string | ||
timestamp: string | ||
[k: string]: unknown | ||
} | ||
export function isRecordEvent(v: unknown): v is RecordEvent { | ||
return ( | ||
isObj(v) && | ||
hasProp(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#recordEvent' | ||
) | ||
} | ||
export function validateRecordEvent(v: unknown): ValidationResult { | ||
return lexicons.validate('tools.ozone.moderation.defs#recordEvent', v) | ||
} | ||
export interface RepoView { | ||
@@ -712,1 +794,49 @@ did: string | ||
} | ||
export interface AccountHosting { | ||
status: | ||
| 'takendown' | ||
| 'suspended' | ||
| 'deleted' | ||
| 'deactivated' | ||
| 'unknown' | ||
| (string & {}) | ||
updatedAt?: string | ||
createdAt?: string | ||
deletedAt?: string | ||
deactivatedAt?: string | ||
reactivatedAt?: string | ||
[k: string]: unknown | ||
} | ||
export function isAccountHosting(v: unknown): v is AccountHosting { | ||
return ( | ||
isObj(v) && | ||
hasProp(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#accountHosting' | ||
) | ||
} | ||
export function validateAccountHosting(v: unknown): ValidationResult { | ||
return lexicons.validate('tools.ozone.moderation.defs#accountHosting', v) | ||
} | ||
export interface RecordHosting { | ||
status: 'deleted' | 'unknown' | (string & {}) | ||
updatedAt?: string | ||
createdAt?: string | ||
deletedAt?: string | ||
[k: string]: unknown | ||
} | ||
export function isRecordHosting(v: unknown): v is RecordHosting { | ||
return ( | ||
isObj(v) && | ||
hasProp(v, '$type') && | ||
v.$type === 'tools.ozone.moderation.defs#recordHosting' | ||
) | ||
} | ||
export function validateRecordHosting(v: unknown): ValidationResult { | ||
return lexicons.validate('tools.ozone.moderation.defs#recordHosting', v) | ||
} |
@@ -31,2 +31,5 @@ /** | ||
| ToolsOzoneModerationDefs.ModEventTag | ||
| ToolsOzoneModerationDefs.AccountEvent | ||
| ToolsOzoneModerationDefs.IdentityEvent | ||
| ToolsOzoneModerationDefs.RecordEvent | ||
| { $type: string; [k: string]: unknown } | ||
@@ -33,0 +36,0 @@ subject: |
@@ -24,2 +24,12 @@ /** | ||
reviewedAfter?: string | ||
/** Search subjects where the associated record/account was deleted after a given timestamp */ | ||
hostingDeletedAfter?: string | ||
/** Search subjects where the associated record/account was deleted before a given timestamp */ | ||
hostingDeletedBefore?: string | ||
/** Search subjects where the associated record/account was updated after a given timestamp */ | ||
hostingUpdatedAfter?: string | ||
/** Search subjects where the associated record/account was updated before a given timestamp */ | ||
hostingUpdatedBefore?: string | ||
/** Search subjects by the status of the associated record/account */ | ||
hostingStatuses?: string[] | ||
/** Search subjects reviewed before a given timestamp */ | ||
@@ -26,0 +36,0 @@ reviewedBefore?: string |
@@ -172,3 +172,3 @@ /* | ||
if (this.facets) { | ||
this.facets.sort(facetSort) | ||
this.facets = this.facets.filter(facetFilter).sort(facetSort) | ||
} | ||
@@ -354,13 +354,19 @@ if (opts?.cleanNewlines) { | ||
if (this.facets) { | ||
const promises: Promise<void>[] = [] | ||
for (const facet of this.facets) { | ||
for (const feature of facet.features) { | ||
if (AppBskyRichtextFacet.isMention(feature)) { | ||
const did = await agent.com.atproto.identity | ||
.resolveHandle({ handle: feature.did }) | ||
.catch((_) => undefined) | ||
.then((res) => res?.data.did) | ||
feature.did = did || '' | ||
promises.push( | ||
agent.com.atproto.identity | ||
.resolveHandle({ handle: feature.did }) | ||
.then((res) => res?.data.did) | ||
.catch((_) => undefined) | ||
.then((did) => { | ||
feature.did = did || '' | ||
}), | ||
) | ||
} | ||
} | ||
} | ||
await Promise.allSettled(promises) | ||
this.facets.sort(facetSort) | ||
@@ -383,4 +389,8 @@ } | ||
const facetSort = (a, b) => a.index.byteStart - b.index.byteStart | ||
const facetSort = (a: Facet, b: Facet) => a.index.byteStart - b.index.byteStart | ||
const facetFilter = (facet: Facet) => | ||
// discard negative-length facets. zero-length facets are valid | ||
facet.index.byteStart <= facet.index.byteEnd | ||
function entitiesToFacets(text: UnicodeString, entities: Entity[]): Facet[] { | ||
@@ -387,0 +397,0 @@ const facets: Facet[] = [] |
@@ -661,2 +661,46 @@ import { RichText } from '../src' | ||
}) | ||
it("doesn't duplicate text when negative-length facets are present", () => { | ||
const input = { | ||
text: 'hello world', | ||
facets: [ | ||
// invalid zero-length | ||
{ | ||
features: [], | ||
index: { | ||
byteStart: 6, | ||
byteEnd: 0, | ||
}, | ||
}, | ||
// valid normal facet | ||
{ | ||
features: [], | ||
index: { | ||
byteEnd: 11, | ||
byteStart: 6, | ||
}, | ||
}, | ||
// valid zero-length | ||
{ | ||
features: [], | ||
index: { | ||
byteEnd: 0, | ||
byteStart: 0, | ||
}, | ||
}, | ||
], | ||
} | ||
const rt = new RichText(input) | ||
let output = '' | ||
for (const segment of rt.segments()) { | ||
output += segment.text | ||
} | ||
expect(output).toEqual(input.text) | ||
// invalid one should have been removed | ||
expect(rt.facets?.length).toEqual(2) | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3851968
1297
86961