Skip to content

Commit af9d1c9

Browse files
committed
Specific resource fixes for annotation targets
1 parent 3018884 commit af9d1c9

3 files changed

Lines changed: 37 additions & 14 deletions

File tree

__tests__/presentation-4-parser/normalized-defaults.test.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,11 @@ describe("presentation-4 normalized defaults", () => {
157157
]);
158158
expect((normalizedRange.items as unknown[]).length).toBe(0);
159159

160-
const normalizedTargetEntity = result.entities.ContentResource[(normalizedAnnotation as any).target.id] as any;
161-
expect(normalizedTargetEntity).toBeTruthy();
162-
expectArrayFields(normalizedTargetEntity, ["selector", "transform"]);
163-
expect(Array.isArray(normalizedTargetEntity.source)).toBe(false);
160+
const normalizedTarget = (normalizedAnnotation as any).target;
161+
expect(normalizedTarget.type).toBe("SpecificResource");
162+
expectArrayFields(normalizedTarget, ["selector", "transform"]);
163+
expect(Array.isArray(normalizedTarget.source)).toBe(false);
164+
expect(result.entities.ContentResource[normalizedTarget.id]).toBeUndefined();
164165
});
165166

166167
test("applies canonical defaults for legacy-upgraded resources", () => {
@@ -202,12 +203,13 @@ describe("presentation-4 normalized defaults", () => {
202203
const result = normalize(legacyManifest as any);
203204
const annotation = result.entities.Annotation["https://example.org/canvas/1/annotation/1"] as any;
204205
const range = result.entities.Range["https://example.org/range/1"] as any;
205-
const target = result.entities.ContentResource[annotation.target.id] as any;
206+
const target = annotation.target;
206207

207208
expect(annotation.body).toBeNull();
208209
expect(Array.isArray(range.supplementary)).toBe(true);
209210
expectArrayFields(target, ["selector", "transform"]);
210211
expect(Array.isArray(target.source)).toBe(false);
212+
expect(result.entities.ContentResource[target.id]).toBeUndefined();
211213
});
212214

213215
test("wraps multiple body/target values in minted List resources", () => {
@@ -247,7 +249,7 @@ describe("presentation-4 normalized defaults", () => {
247249
const normalized = normalize(manifest as any);
248250
const annotation = normalized.entities.Annotation["https://example.org/canvas/1/annotation/1"] as any;
249251
const body = normalized.entities.ContentResource[annotation.body.id] as any;
250-
const target = normalized.entities.ContentResource[annotation.target.id] as any;
252+
const target = annotation.target;
251253

252254
expect(annotation.body.id.startsWith("vault://iiif-parser/v4/ContentResource/")).toBe(true);
253255
expect(annotation.target.id.startsWith("vault://iiif-parser/v4/ContentResource/")).toBe(true);
@@ -257,6 +259,8 @@ describe("presentation-4 normalized defaults", () => {
257259
expect(Array.isArray(target.items)).toBe(true);
258260
expect(body.items).toHaveLength(2);
259261
expect(target.items).toHaveLength(2);
262+
expect(target.items[0].type).toBe("SpecificResource");
263+
expect(normalized.entities.ContentResource[annotation.target.id]).toBeUndefined();
260264
});
261265

262266
test("defaults annotation collection paging fields", () => {

__tests__/presentation-4-parser/specific-resource-parity.test.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe("presentation-4 specific resource parity", () => {
5151
const normalizedAnnotation = result.entities.Annotation["https://example.org/canvas/1/annotation/1"] as any;
5252
const normalizedStart = result.entities.ContentResource[normalizedManifest.start.id] as any;
5353
const normalizedRangeItem = result.entities.ContentResource[normalizedRange.items[0].id] as any;
54-
const normalizedTarget = result.entities.ContentResource[normalizedAnnotation.target.id] as any;
54+
const normalizedTarget = normalizedAnnotation.target;
5555
const startSelector = normalizedStart.selector[0];
5656
const rangeSelector = normalizedRangeItem.selector[0];
5757
const targetSelector = normalizedTarget.selector[0];
@@ -68,11 +68,12 @@ describe("presentation-4 specific resource parity", () => {
6868
expect(rangeSelector.type).toBe("FragmentSelector");
6969
expect(rangeSelector.value).toBe("t=0,10");
7070

71-
expect(normalizedAnnotation.target.type).toBe("ContentResource");
71+
expect(normalizedAnnotation.target.type).toBe("SpecificResource");
7272
expect(normalizedAnnotation.target.id.startsWith("vault://iiif-parser/v4/SpecificResource/")).toBe(true);
7373
expect(normalizedTarget.source.id).toBe("https://example.org/canvas/1");
7474
expect(targetSelector.type).toBe("FragmentSelector");
7575
expect(targetSelector.value).toBe("xywh=10,20,30,40");
76+
expect(result.entities.ContentResource[normalizedAnnotation.target.id]).toBeUndefined();
7677

7778
expect(targetSelector).toMatchInlineSnapshot(`
7879
{
@@ -138,13 +139,14 @@ describe("presentation-4 specific resource parity", () => {
138139

139140
const normalized = normalize(manifest as any);
140141
const annotation = normalized.entities.Annotation["https://example.org/canvas/1/annotation/1"] as any;
141-
const target = normalized.entities.ContentResource[annotation.target.id] as any;
142+
const target = annotation.target;
142143
const targetSelector = target.selector[0];
143144

144-
expect(annotation.target.type).toBe("ContentResource");
145+
expect(annotation.target.type).toBe("SpecificResource");
145146
expect(target.source.id).toBe("https://example.org/canvas/1");
146147
expect(targetSelector.type).toBe("FragmentSelector");
147148
expect(targetSelector.value).toBe("xywh=11,22,33,44");
149+
expect(normalized.entities.ContentResource[annotation.target.id]).toBeUndefined();
148150

149151
const serialized = serialize<any>(
150152
{
@@ -210,10 +212,11 @@ describe("presentation-4 specific resource parity", () => {
210212

211213
const normalized = normalize(manifest as any);
212214
const annotation = normalized.entities.Annotation["https://example.org/canvas/1/annotation/1"] as any;
213-
const target = normalized.entities.ContentResource[annotation.target.id] as any;
215+
const target = annotation.target;
214216

215217
expect(target.source.id).toBe("https://example.org/canvas/1");
216218
expect(target.source.type).toBe("Canvas");
217219
expect(Array.isArray(target.source)).toBe(false);
220+
expect(normalized.entities.ContentResource[target.id]).toBeUndefined();
218221
});
219222
});

src/presentation-4/normalize.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,19 @@ function addFlagForExternalResource<T extends { items?: unknown }>(resource: T):
349349
return resource;
350350
}
351351

352+
function isAnnotationTargetContext(context: TraversalContext): boolean {
353+
return context.path.includes(".target");
354+
}
355+
356+
function skipOnAnnotationTarget<T extends (resource: any, context: TraversalContext) => any>(traversal: T): T {
357+
return (((resource: any, context: TraversalContext) => {
358+
if (isAnnotationTargetContext(context)) {
359+
return resource;
360+
}
361+
return traversal(resource, context);
362+
}) as unknown) as T;
363+
}
364+
352365
function ensureRangeSupplementaryArray<T extends { supplementary?: unknown }>(resource: T): T {
353366
if (resource && typeof resource === "object") {
354367
const supplementary = (resource as any).supplementary;
@@ -447,13 +460,16 @@ export function normalize(input: unknown): NormalizeResult {
447460
if (!isLegacySource) {
448461
contentResourceTraversals.push(ensureDefaultFields(emptyContentResource));
449462
}
450-
contentResourceTraversals.push(map("ContentResource"), record("ContentResource"));
463+
contentResourceTraversals.push(
464+
skipOnAnnotationTarget(map("ContentResource")),
465+
skipOnAnnotationTarget(record("ContentResource"))
466+
);
451467

452468
const specificResourceTraversals: Array<(resource: any, context: TraversalContext) => any> = [
453469
withId("SpecificResource", diagnostics),
454470
ensureDefaultFields(emptySpecificResource),
455-
map("SpecificResource"),
456-
record("SpecificResource"),
471+
skipOnAnnotationTarget(map("SpecificResource")),
472+
skipOnAnnotationTarget(record("SpecificResource")),
457473
];
458474

459475
const traversal = new Traverse(

0 commit comments

Comments
 (0)