@allmaps/iiif-parser
Version:
Allmaps IIIF parser
166 lines (165 loc) • 5.59 kB
JavaScript
// Presentation API 2.1 - Manifest
// https://iiif.io/api/presentation/2.1/#manifest
import { z } from 'zod';
import { ImageServiceSchema } from './image-service.js';
import { NavPlaceSchema, NavDateSchema } from '../schemas/shared.js';
import { ensureArray } from '../lib/convert.js';
export const SingleValue2Schema = z
.union([z.string(), z.number(), z.boolean()])
.transform((val) => String(val));
export const Value2Schema = z.union([
SingleValue2Schema.array(),
SingleValue2Schema
]);
export const RelatedItem2Schema = z.object({
'@id': z.string().url(),
format: z.string().optional(),
label: Value2Schema.optional()
});
export const Related2Schema = z.union([
RelatedItem2Schema.array(),
RelatedItem2Schema,
SingleValue2Schema
]);
export const ThumbnailItem2Schema = z.union([
z.string(),
z.object({
'@id': z.string().url(),
'@type': z.string().optional(),
format: z.string().optional(),
height: z.number().optional(),
width: z.number().optional()
})
]);
export const Thumbnail2Schema = z
.union([ThumbnailItem2Schema.array(), ThumbnailItem2Schema])
.transform(ensureArray);
export const RenderingItem2Schema = z.object({
'@id': z.string().url(),
'@type': z.string().optional(),
label: Value2Schema.optional(),
format: z.string().optional()
});
export const Rendering2Schema = z
.union([RenderingItem2Schema.array(), RenderingItem2Schema])
.transform(ensureArray);
const ValidLanguageValue2Schema = z
.union([
z.object({ '@value': Value2Schema, '@language': z.string().optional() }),
// This is invalid but some IIIF manifests use this incorrect format
z.object({ value: Value2Schema, language: z.string().optional() })
])
.transform((val) => {
if ('value' in val) {
return {
'@value': val.value,
'@language': val.language
};
}
else {
return val;
}
});
export const LanguageValue2Schema = ValidLanguageValue2Schema;
export const PossibleLanguageValue2Schema = z.union([
LanguageValue2Schema.array(),
LanguageValue2Schema,
Value2Schema
]);
export const Attribution2Schema = z.union([
z.string(),
PossibleLanguageValue2Schema
]);
const ValidMetadataItem2Schema = z.object({
label: PossibleLanguageValue2Schema.optional(),
value: PossibleLanguageValue2Schema.optional()
});
export const MetadataItem2Schema = z
.union([
ValidMetadataItem2Schema,
// Catchall for incorrect values
z.any()
])
.transform((val) => {
const { success, data } = ValidMetadataItem2Schema.safeParse(val);
if (success) {
return data;
}
});
export const Metadata2Schema = MetadataItem2Schema.array();
export const ImageResource2Schema = z.object({
width: z.number().int().optional(),
height: z.number().int().optional(),
service: ImageServiceSchema
});
export const Annotation2Schema = z.object({
resource: ImageResource2Schema
});
export const Canvas2Schema = z.object({
'@id': z.string().url(),
'@type': z.literal('sc:Canvas'),
width: z.number().int(),
height: z.number().int(),
images: Annotation2Schema.array().length(1),
label: PossibleLanguageValue2Schema.optional(),
description: PossibleLanguageValue2Schema.optional(),
related: Related2Schema.optional(),
attribution: Attribution2Schema.optional(),
thumbnail: Thumbnail2Schema.optional(),
rendering: Rendering2Schema.optional(),
metadata: Metadata2Schema.optional(),
navDate: NavDateSchema.optional(),
navPlace: NavPlaceSchema.optional()
});
const Sequence2Schema = z.object({
canvases: Canvas2Schema.array().nonempty()
});
export const Manifest2Schema = z.object({
'@id': z.string().url(),
'@type': z.literal('sc:Manifest'),
sequences: Sequence2Schema.array().length(1),
label: PossibleLanguageValue2Schema.optional(),
description: PossibleLanguageValue2Schema.optional(),
metadata: Metadata2Schema.optional(),
related: Related2Schema.optional(),
attribution: Attribution2Schema.optional(),
rendering: Rendering2Schema.optional(),
thumbnail: Thumbnail2Schema.optional(),
navDate: NavDateSchema.optional(),
navPlace: NavPlaceSchema.optional()
});
// @ts-expect-error - Lazy type is not correctly inferred
export const EmbeddedManifest2Schema = z.lazy(() => z.object({
'@id': z.string().url(),
'@type': z.literal('sc:Manifest'),
label: PossibleLanguageValue2Schema.optional()
}));
// @ts-expect-error - Lazy type is not correctly inferred
export const Collection2Schema = z.lazy(() => z.object({
'@id': z.string().url(),
'@type': z.literal('sc:Collection'),
manifests: EmbeddedManifest2Schema.array().optional(),
collections: Collection2Schema.array().optional(),
members: z
.union([
EmbeddedManifest2Schema,
Collection2Schema,
EmbeddedCollection2Schema
])
.array()
.optional(),
label: PossibleLanguageValue2Schema.optional(),
description: PossibleLanguageValue2Schema.optional(),
metadata: Metadata2Schema.optional(),
related: Related2Schema.optional(),
attribution: Attribution2Schema.optional(),
thumbnail: Thumbnail2Schema.optional(),
rendering: Rendering2Schema.optional(),
navDate: NavDateSchema.optional(),
navPlace: NavPlaceSchema.optional()
}));
export const EmbeddedCollection2Schema = z.object({
'@id': z.string().url(),
'@type': z.literal('sc:Collection'),
label: PossibleLanguageValue2Schema.optional()
});