UNPKG

epubavocado

Version:

I am an EPUB object model aspiring to be standards compliant.

390 lines (389 loc) 13.6 kB
import { Entity } from './mixins/entity.js'; import { I18n } from './package/mixins/i18n.js'; import { ID } from './package/mixins/id.js'; import { Properties } from './package/mixins/properties.js'; import { Resource } from './mixins/resource.js'; import { Value } from './package/mixins/value.js'; import { splitRelAttribute, toArray } from '../util.js'; import { prefixMap, select } from '../xpath.js'; import { ManifestItem } from './package/manifest-item.js'; import { Manifest } from './package/manifest.js'; import { SpineItem } from './package/spine-item.js'; import { Spine } from './package/spine.js'; import { idFilter, attributeFilter, anyPropertiesFilter, allPropertiesFilter, anyRelFilter, allRelFilter, } from './package/util.js'; export { ManifestItem, Manifest, SpineItem, Spine }; const nodeTypeMap = () => ({ 'opf:package': Package, 'opf:metadata': Metadata, 'opf:manifest': Manifest, 'opf:spine': Spine, 'opf:meta': Meta, 'opf:item': ManifestItem, 'opf:itemref': SpineItem, 'opf:link': Link, // 'opf:collection': Collection, 'dc:identifier': Identifier, 'dc:title': Title, 'dc:language': Language, 'dc:contributor': Contributor, 'dc:coverage': Coverage, 'dc:creator': Creator, 'dc:date': Date, 'dc:description': Description, 'dc:format': Format, 'dc:publisher': Publisher, 'dc:relation': Relation, 'dc:rights': Rights, 'dc:source': Source, 'dc:subject': Subject, 'dc:type': Type, }); function MetaProperties(Base) { return class MetaProperties extends Base { _resolveMetaProperty(property, constructor = Meta) { return toArray(this._resolveMetaPropertyList(property, constructor))[0]; } _resolveMetaPropertyList(property, constructor = Meta) { var _a; const id = this.id(); if (!id) { return []; } const propertyMap = (_a = this._context.metadata()) === null || _a === void 0 ? void 0 : _a._metaPropertyMap[id]; if (!propertyMap) { return []; } const metaNodes = propertyMap[property]; if (!metaNodes) { return []; } return metaNodes.map((node) => new constructor(node, this._context)); } alternateScript() { return this.alternateScripts()[0]; } alternateScripts() { return this._resolveMetaPropertyList('alternate-script'); } displaySeq() { return this._resolveMetaProperty('display-seq'); } fileAs() { return this._resolveMetaProperty('file-as'); } groupPosition() { return this._resolveMetaProperty('group-position'); } metaAuth() { return this._resolveMetaProperty('meta-auth'); } }; } function MetaAttributes(Base) { return class MetaAttributes extends Base { property() { return this._resolve('./@property'); } scheme() { return this._resolve('./@scheme'); } }; } function Refines(Base) { return class Refines extends Base { refines() { const refines = this._resolve('./@refines'); if (!refines) { return null; } // drop the # prefix const idRefined = refines[0] === '#' ? refines.substr(1) : refines; const node = this._context._select(`//*[@id='${idRefined}']`); if (!node) { return null; } const name = node.localName; const namespace = node.namespaceURI; if (!namespace) { return null; } const prefix = prefixMap[namespace]; const typeConstructor = nodeTypeMap()[`${prefix}:${name}`]; if (!typeConstructor) { return null; } return new typeConstructor(node, this._context); } }; } export class Meta extends MetaProperties(MetaAttributes(Refines(I18n(Value(ID(Entity)))))) { } export class Identifier extends Value(MetaProperties(ID(Entity))) { identifierType() { return this._resolveMetaProperty('identifier-type'); } } export class Title extends Value(I18n(MetaProperties(ID(Entity)))) { titleType() { return this._resolveMetaProperty('title-type'); } } export class Language extends Value(MetaProperties(ID(Entity))) { } export class Contributor extends Value(I18n(MetaProperties(ID(Entity)))) { role() { return this._resolveMetaProperty('role'); } } export class Coverage extends Value(I18n(MetaProperties(ID(Entity)))) { } export class Creator extends Contributor { } export class Date extends Value(MetaProperties(ID(Entity))) { } export class Description extends Value(I18n(MetaProperties(ID(Entity)))) { } export class Format extends Value(MetaProperties(ID(Entity))) { } export class Publisher extends Value(I18n(MetaProperties(ID(Entity)))) { } export class Relation extends Value(I18n(MetaProperties(ID(Entity)))) { } export class Rights extends Value(I18n(MetaProperties(ID(Entity)))) { } export class Source extends Identifier { sourceOf() { return this._resolveMetaProperty('source-of'); } } export class Subject extends Value(I18n(MetaProperties(ID(Entity)))) { authority() { return this._resolveMetaProperty('authority'); } term() { return this._resolveMetaProperty('term'); } } export class Type extends Value(MetaProperties(ID(Entity))) { } export class BelongsToCollection extends Value(I18n(Refines(MetaAttributes(MetaProperties(ID(Entity)))))) { identifier() { return this._resolveMetaProperty('dcterms:identifier'); } collectionType() { return this._resolveMetaProperty('collection-type'); } belongsToCollection() { return this.belongsToCollections()[0]; } belongsToCollections() { return this._resolveMetaPropertyList('belongs-to-collection', BelongsToCollection); } } export class Link extends Resource(Properties(Refines(ID(Entity)))) { rel() { return this.rels()[0]; } rels() { const rel = this._resolve('./@rel'); if (rel) { return splitRelAttribute(rel); } return []; } } export class Metadata extends ID(Entity) { constructor(node, context) { super(node, context); this._metaPropertyMap = {}; const metaRefiningSelected = toArray(this._selectAll('./opf:meta[@refines and @property]')); metaRefiningSelected.forEach((selectedValue) => { const node = selectedValue; if (!node) { return; } const refinesAttr = select('./@refines', node); if (!refinesAttr) { return; } const refinesValue = refinesAttr.value; // drop the # prefix const idRefined = refinesValue[0] === '#' ? refinesValue.substr(1) : refinesValue; const propertyAttr = select('./@property', node); if (!propertyAttr) { return; } const property = propertyAttr.value; if (!this._metaPropertyMap[idRefined]) { this._metaPropertyMap[idRefined] = {}; } if (!this._metaPropertyMap[idRefined][property]) { this._metaPropertyMap[idRefined][property] = []; } this._metaPropertyMap[idRefined][property].push(node); }); } identifier({ id }) { return this._resolve(`./dc:identifier${idFilter(id)}`, Identifier); } modified() { const node = this._select("./opf:meta[@property='dcterms:modified' and not(@refines)]"); if (node) { return new Meta(node, this._context); } } title({ id }) { return this.titles({ ids: id ? [id] : [] })[0]; } titles({ ids }) { return this._resolveAll(`./dc:title${idFilter(ids)}`, Title); } language({ id }) { return this.languages({ ids: id ? [id] : [] })[0]; } languages({ ids }) { return this._resolveAll(`./dc:language${idFilter(ids)}`, Language); } contributor({ id }) { return this.contributors({ ids: id ? [id] : [] })[0]; } contributors({ ids }) { return this._resolveAll(`./dc:contributor${idFilter(ids)}`, Contributor); } coverage({ id }) { return this.coverages({ ids: id ? [id] : [] })[0]; } coverages({ ids }) { return this._resolveAll(`./dc:coverage${idFilter(ids)}`, Coverage); } creator({ id }) { return this.creators({ ids: id ? [id] : [] })[0]; } creators({ ids }) { return this._resolveAll(`./dc:creator${idFilter(ids)}`, Creator); } date({ id }) { return this._resolve(`./dc:date${idFilter(id)}`, Date); } description({ id }) { return this.descriptions({ ids: id ? [id] : [] })[0]; } descriptions({ ids }) { return this._resolveAll(`./dc:description${idFilter(ids)}`, Description); } format({ id }) { return this.formats({ ids: id ? [id] : [] })[0]; } formats({ ids }) { return this._resolveAll(`./dc:format${idFilter(ids)}`, Format); } publisher({ id }) { return this.publishers({ ids: id ? [id] : [] })[0]; } publishers({ ids }) { return this._resolveAll(`./dc:publisher${idFilter(ids)}`, Publisher); } relation({ id }) { return this.relations({ ids: id ? [id] : [] })[0]; } relations({ ids }) { return this._resolveAll(`./dc:relation${idFilter(ids)}`, Relation); } rights({ id }) { return this.rightses({ ids: id ? [id] : [] })[0]; } rightses({ ids }) { return this._resolveAll(`./dc:rights${idFilter(ids)}`, Rights); } source({ id }) { return this.sources({ ids: id ? [id] : [] })[0]; } sources({ ids }) { return this._resolveAll(`./dc:source${idFilter(ids)}`, Source); } subject({ id }) { return this.subjects({ ids: id ? [id] : [] })[0]; } subjects({ ids }) { return this._resolveAll(`./dc:subject${idFilter(ids)}`, Subject); } type({ id }) { return this.types({ ids: id ? [id] : [] })[0]; } types({ ids }) { return this._resolveAll(`./dc:type${idFilter(ids)}`, Type); } belongsToCollection({ id }) { return this.belongsToCollections({ ids: id ? [id] : [] })[0]; } belongsToCollections({ ids, } = {}) { return this._resolveAll(`./opf:meta${idFilter(ids)}[@property='belongs-to-collection' and not(@refines)]`, BelongsToCollection); } meta({ id, property, refines, } = {}) { return this.metas({ ids: id ? [id] : [], property, refines, })[0]; } metas({ ids, property, refines, } = {}) { return this._resolveAll(`./opf:meta${idFilter(ids)}${attributeFilter('@property', property, 'and')}${attributeFilter('@refines', refines ? `#${refines}` : undefined, 'or')}`, Meta); } link({ id, href, anyProperties, allProperties, onlyProperties, anyRel, allRel, onlyRel, } = {}) { return this.links({ ids: id ? [id] : [], href, anyProperties, allProperties, onlyProperties, anyRel, allRel, onlyRel, })[0]; } links(args = {}) { const { ids, href, anyProperties, allProperties, onlyProperties, anyRel, allRel, onlyRel, } = args; if (onlyProperties) { return this.links(Object.assign(Object.assign({}, args), { allProperties: onlyProperties, onlyProperties: undefined })).filter((item) => toArray(item.properties()).length === onlyProperties.length); } if (onlyRel) { return this.links(Object.assign(Object.assign({}, args), { allRel: onlyRel, onlyRel: undefined })).filter((item) => toArray(item.rels()).length === onlyRel.length); } const expression = `./opf:link${idFilter(ids)}${attributeFilter('@href', href)}${anyPropertiesFilter(anyProperties)}${allPropertiesFilter(allProperties)}${anyRelFilter(anyRel)}${allRelFilter(allRel)}`; return this._resolveAll(expression, Link); } } export class Package extends I18n(ID(Entity)) { constructor(doc) { super(select('/opf:package', doc)); } version() { return this._resolve('./@version'); } uniqueIdentifier() { var _a; const uniqueIdentifierIDRef = this._resolve('./@unique-identifier'); if (uniqueIdentifierIDRef) { return (_a = this.metadata()) === null || _a === void 0 ? void 0 : _a.identifier({ id: uniqueIdentifierIDRef }); } } releaseIdentifier() { var _a; const uniqueIdentifier = this.uniqueIdentifier(); const modified = (_a = this.metadata()) === null || _a === void 0 ? void 0 : _a.modified(); if (uniqueIdentifier && modified) { return `${uniqueIdentifier.value()}@${modified.value()}`; } } metadata() { return (this._metadata = this._metadata || this._resolve('./opf:metadata', Metadata)); } spine() { return (this._spine = this._spine || this._resolve('./opf:spine', Spine)); } manifest() { return (this._manifest = this._manifest || this._resolve('./opf:manifest', Manifest)); } }