Commit 1b034f3c authored by Diegodlh's avatar Diegodlh
Browse files

Implement Citation object

parent 629a9a1f
import { Citation } from "./citation";
import {
MediaWikiCitation,
MediaWikiBaseFieldCitation,
SimpleCitoidCitation,
} from "./citationTypes";
import { SimpleCitoidFields } from "./fieldTypes";
const mwCitation: MediaWikiCitation = {
// required
itemType: "case",
url: "https://example.com",
// non-base title
caseName: "case name",
// special
tags: [
{ tag: "first tag", type: 0 },
{ tag: "second tag", type: 0 },
],
// base regular
abstractNote: "abstract note",
// non-base regular
artworkMedium: "medium",
// base creator
editor: [
["First", "Editor"],
["Second", "Editor"],
],
// non-base creator
contributor: [
["First", "Author"],
["Second", "Author"],
],
};
const mwbCitation: MediaWikiCitation = {
itemType: "case",
url: "https://example.com",
title: "case name",
tags: [
{ tag: "first tag", type: 0 },
{ tag: "second tag", type: 0 },
],
abstractNote: "abstract note",
medium: "medium",
editor: [
["First", "Editor"],
["Second", "Editor"],
],
author: [
["First", "Author"],
["Second", "Author"],
],
};
const simpleCitation: SimpleCitoidCitation = {
itemType: "case",
url: "https://example.com",
title: "case name",
tags: ["first tag", "second tag"],
abstractNote: "abstract note",
medium: "medium",
editorFirst: ["First", "Second"],
editorLast: ["Editor", "Editor"],
authorFirst: ["First", "Second"],
authorLast: ["Author", "Author"],
};
it("creates citation object from mediawiki citation", () => {
const citation = new Citation(mwCitation);
expect(citation.mediawiki).toEqual(mwCitation);
});
it("converts to mediawiki-basefields citation", () => {
const citation = new Citation(mwCitation);
expect(citation.mediawikibase).toEqual(mwbCitation);
});
it("converts to simple citation", () => {
const citation = new Citation(mwCitation);
expect(citation.simple).toEqual(simpleCitation);
});
import { import {
MediaWikiBaseFieldCitation, MediaWikiBaseFieldCitation,
MediaWikiCitation,
SimpleCitoidCitation, SimpleCitoidCitation,
} from "./citationTypes"; } from "./citationTypes";
import { BASE_CREATOR_TYPES } from "./creatorTypes"; import { BASE_CREATOR_TYPES } from "./creatorTypes";
import { SIMPLE_CITOID_FIELDS } from "./keyTypes"; import {
SIMPLE_CITOID_FIELDS,
baseFieldMap,
isRegularField,
isCreatorField,
} from "./keyTypes";
export class Citation {
private citation: MediaWikiCitation;
constructor(citation: MediaWikiCitation | MediaWikiBaseFieldCitation) {
this.citation = citation;
}
export function simplifyCitation( get mediawiki(): MediaWikiCitation {
mwbCitation: MediaWikiBaseFieldCitation return this.citation;
): SimpleCitoidCitation { }
const simpleCitation: SimpleCitoidCitation = {
itemType: mwbCitation.itemType, get mediawikibase(): MediaWikiBaseFieldCitation {
title: mwbCitation.title, // fixme: consider improving implementation
url: mwbCitation.url, const mwbCitation: MediaWikiBaseFieldCitation = {
tags: mwbCitation.tags?.map((tag) => tag.tag), // required
}; itemType: this.citation.itemType,
// split mediawiki creator arrays into creatorFirst and creatorLast arrays url: this.citation.url,
for (const baseCreatorType of BASE_CREATOR_TYPES) { // title
const creators = mwbCitation[baseCreatorType]; title: (this.citation.title ||
if (creators) { this.citation.caseName ||
simpleCitation[`${baseCreatorType}First`] = creators.map( this.citation.subject ||
(creator) => creator[0] this.citation.nameOfAct)!,
); // special
simpleCitation[`${baseCreatorType}Last`] = creators.map( tags: this.citation.tags,
(creator) => creator[1] key: this.citation.key,
); version: this.citation.version,
// mediawiki
isbn: this.citation.isbn,
issn: this.citation.issn,
PMCID: this.citation.PMCID,
PMID: this.citation.PMID,
oclc: this.citation.oclc,
};
for (const field of Object.keys(this.citation) as Array<
keyof typeof this.citation
>) {
if (isRegularField(field)) {
const baseField = baseFieldMap.get(field);
if (baseField !== undefined && isRegularField(baseField)) {
mwbCitation[baseField] = this.citation[field];
} else {
throw new Error(
`Regular field "${field} not mapped to a regular base field!`
);
}
} else if (isCreatorField(field)) {
const baseField = baseFieldMap.get(field);
if (baseField !== undefined && isCreatorField(baseField)) {
mwbCitation[baseField] = this.citation[field];
} else {
throw new Error(
`Creator field "${field} not mapped to a creator base field!`
);
}
}
} }
return mwbCitation;
} }
for (const field of SIMPLE_CITOID_FIELDS) {
if ( get simple(): SimpleCitoidCitation {
field in mwbCitation && const mwbCitation = this.mediawikibase;
!(field in simpleCitation) && const simpleCitation: SimpleCitoidCitation = {
field !== "itemType" itemType: mwbCitation.itemType,
) { title: mwbCitation.title,
const value = mwbCitation[field as keyof MediaWikiBaseFieldCitation] as url: mwbCitation.url,
| string tags: mwbCitation.tags?.map((tag) => tag.tag),
| Array<string>; };
simpleCitation[field] = value; // split mediawiki creator arrays into creatorFirst and creatorLast arrays
for (const baseCreatorType of BASE_CREATOR_TYPES) {
const creators = mwbCitation[baseCreatorType];
if (creators) {
simpleCitation[`${baseCreatorType}First`] = creators.map(
(creator) => creator[0]
);
simpleCitation[`${baseCreatorType}Last`] = creators.map(
(creator) => creator[1]
);
}
}
for (const field of SIMPLE_CITOID_FIELDS) {
if (
field in mwbCitation &&
!(field in simpleCitation) &&
field !== "itemType"
) {
const value = mwbCitation[field as keyof MediaWikiBaseFieldCitation] as
| string
| Array<string>;
simpleCitation[field] = value;
}
} }
return simpleCitation;
} }
return simpleCitation;
} }
import { import {
RequiredFields, RequiredFields,
BaseTitleFields, BaseTitleFields,
NonBaseTitleFields, TitleFields,
SpecialFields, SpecialFields,
BaseFields, BaseRegularFields,
NonBaseFields, NonBaseRegularFields,
BaseCreatorFields, BaseCreatorFields,
NonBaseCreatorFields, NonBaseCreatorFields,
MediaWikiFields, MediaWikiFields,
...@@ -16,11 +16,11 @@ import { REQUIRED_FIELDS, TITLE_FIELDS } from "./keyTypes"; ...@@ -16,11 +16,11 @@ import { REQUIRED_FIELDS, TITLE_FIELDS } from "./keyTypes";
// Citoid citation types // Citoid citation types
export type MediaWikiCitation = RequiredFields & export type MediaWikiCitation = RequiredFields &
(BaseTitleFields | NonBaseTitleFields) & TitleFields &
Partial< Partial<
SpecialFields & SpecialFields &
BaseFields & BaseRegularFields &
NonBaseFields & NonBaseRegularFields &
BaseCreatorFields & BaseCreatorFields &
NonBaseCreatorFields & NonBaseCreatorFields &
MediaWikiFields MediaWikiFields
...@@ -28,11 +28,15 @@ export type MediaWikiCitation = RequiredFields & ...@@ -28,11 +28,15 @@ export type MediaWikiCitation = RequiredFields &
export type MediaWikiBaseFieldCitation = RequiredFields & export type MediaWikiBaseFieldCitation = RequiredFields &
BaseTitleFields & BaseTitleFields &
Partial<SpecialFields & BaseFields & BaseCreatorFields & MediaWikiFields>; Partial<
SpecialFields & BaseRegularFields & BaseCreatorFields & MediaWikiFields
>;
export type ZoteroCitation = RequiredFields & type ZoteroCitation = RequiredFields &
(BaseTitleFields | NonBaseTitleFields) & TitleFields &
Partial<SpecialFields & BaseFields & NonBaseFields & ZoteroFields>; Partial<
SpecialFields & BaseRegularFields & NonBaseRegularFields & ZoteroFields
>;
export type CitoidCitation = export type CitoidCitation =
| MediaWikiCitation | MediaWikiCitation
......
// Creator types // Creator types
//////////////// ////////////////
// Base creator field key type // Base creator type
export const BASE_CREATOR_TYPES = [ export const BASE_CREATOR_TYPES = [
"attorneyAgent", "attorneyAgent",
"author", "author",
...@@ -25,7 +25,7 @@ export const BASE_CREATOR_TYPES = [ ...@@ -25,7 +25,7 @@ export const BASE_CREATOR_TYPES = [
] as const; ] as const;
export type BaseCreatorType = typeof BASE_CREATOR_TYPES[number]; export type BaseCreatorType = typeof BASE_CREATOR_TYPES[number];
// Non-base creator field key type // Non-base creator type
const NON_BASE_CREATOR_TYPES = [ const NON_BASE_CREATOR_TYPES = [
"artist", "artist",
"cartographer", "cartographer",
...@@ -39,3 +39,13 @@ const NON_BASE_CREATOR_TYPES = [ ...@@ -39,3 +39,13 @@ const NON_BASE_CREATOR_TYPES = [
"sponsor", "sponsor",
] as const; ] as const;
export type NonBaseCreatorType = typeof NON_BASE_CREATOR_TYPES[number]; export type NonBaseCreatorType = typeof NON_BASE_CREATOR_TYPES[number];
// Creator type
type CreatorType = BaseCreatorType | NonBaseCreatorType;
export function isCreatorType(type: unknown): type is CreatorType {
return (
BASE_CREATOR_TYPES.includes(type as BaseCreatorType) ||
NON_BASE_CREATOR_TYPES.includes(type as NonBaseCreatorType)
);
}
...@@ -11,8 +11,8 @@ import { ...@@ -11,8 +11,8 @@ import {
BaseTitleField, BaseTitleField,
NonBaseTitleField, NonBaseTitleField,
SpecialField, SpecialField,
BaseField, BaseRegularField,
NonBaseField, NonBaseRegularField,
BaseCreatorField, BaseCreatorField,
NonBaseCreatorField, NonBaseCreatorField,
SplitBaseCreatorField, SplitBaseCreatorField,
...@@ -36,7 +36,7 @@ assert<Equals<RequiredField, keyof RequiredFields>>(true); ...@@ -36,7 +36,7 @@ assert<Equals<RequiredField, keyof RequiredFields>>(true);
export type BaseTitleFields = { export type BaseTitleFields = {
[key in BaseTitleField]: string; [key in BaseTitleField]: string;
}; };
export type NonBaseTitleFields = OneKey<NonBaseTitleField, string>; export type TitleFields = OneKey<BaseTitleField | NonBaseTitleField, string>;
// Special fields // Special fields
export interface SpecialFields { export interface SpecialFields {
...@@ -47,10 +47,10 @@ export interface SpecialFields { ...@@ -47,10 +47,10 @@ export interface SpecialFields {
assert<Equals<SpecialField, keyof SpecialFields>>(true); assert<Equals<SpecialField, keyof SpecialFields>>(true);
// Base fields // Base fields
export type BaseFields = Record<BaseField, string>; export type BaseRegularFields = Record<BaseRegularField, string>;
// Non-base fields // Non-base fields
export type NonBaseFields = Record<NonBaseField, string>; export type NonBaseRegularFields = Record<NonBaseRegularField, string>;
// Base creator fields // Base creator fields
export type BaseCreatorFields = Record< export type BaseCreatorFields = Record<
...@@ -93,7 +93,7 @@ export type SimpleCitoidFields = Record< ...@@ -93,7 +93,7 @@ export type SimpleCitoidFields = Record<
} & Partial< } & Partial<
Record< Record<
| Exclude<SpecialField, "key" | "version"> | Exclude<SpecialField, "key" | "version">
| BaseField | BaseRegularField
| SplitBaseCreatorField | SplitBaseCreatorField
| Exclude<MediaWikiField, "source">, | Exclude<MediaWikiField, "source">,
string | string[] string | string[]
......
...@@ -2,11 +2,19 @@ import { ...@@ -2,11 +2,19 @@ import {
BaseCreatorType, BaseCreatorType,
NonBaseCreatorType, NonBaseCreatorType,
BASE_CREATOR_TYPES, BASE_CREATOR_TYPES,
isCreatorType,
} from "./creatorTypes"; } from "./creatorTypes";
// Required field key type // Required field key type
export const REQUIRED_FIELDS = ["itemType", "url"] as const; export const REQUIRED_FIELDS = ["itemType", "url"] as const;
export type RequiredField = typeof REQUIRED_FIELDS[number]; export type RequiredField = typeof REQUIRED_FIELDS[number];
// export function isRequiredField(field: unknown): field is RequiredField {
// if (REQUIRED_FIELDS.includes(field as RequiredField)) {
// return true;
// } else {
// return false;
// }
// }
// Title field key types // Title field key types
const BASE_TITLE_FIELDS = ["title"] as const; const BASE_TITLE_FIELDS = ["title"] as const;
...@@ -21,9 +29,16 @@ export const TITLE_FIELDS = [ ...@@ -21,9 +29,16 @@ export const TITLE_FIELDS = [
// Special field key type // Special field key type
const SPECIAL_FIELDS = ["tags", "key", "version"] as const; const SPECIAL_FIELDS = ["tags", "key", "version"] as const;
export type SpecialField = typeof SPECIAL_FIELDS[number]; export type SpecialField = typeof SPECIAL_FIELDS[number];
// export function isSpecialField(field: unknown): field is SpecialField {
// if (SPECIAL_FIELDS.includes(field as SpecialField)) {
// return true;
// } else {
// return false;
// }
// }
// Base field key type // Regular field key types
const BASE_FIELDS = [ const BASE_REGULAR_FIELDS = [
"abstractNote", "abstractNote",
"accessDate", "accessDate",
"applicationNumber", "applicationNumber",
...@@ -79,10 +94,9 @@ const BASE_FIELDS = [ ...@@ -79,10 +94,9 @@ const BASE_FIELDS = [
"versionNumber", "versionNumber",
"volume", "volume",
] as const; ] as const;
export type BaseField = typeof BASE_FIELDS[number]; export type BaseRegularField = typeof BASE_REGULAR_FIELDS[number];
// Non-base field key type const NON_BASE_REGULAR_FIELDS = [
const NON_BASE_FIELDS = [
// NO field is mapped to this field in ANY item type // NO field is mapped to this field in ANY item type
"artworkMedium", "artworkMedium",
"audioFileType", "audioFileType",
...@@ -90,7 +104,6 @@ const NON_BASE_FIELDS = [ ...@@ -90,7 +104,6 @@ const NON_BASE_FIELDS = [
"billNumber", "billNumber",
"blogTitle", "blogTitle",
"bookTitle", "bookTitle",
"caseName",
"codePages", "codePages",
"codeVolume", "codeVolume",
"company", "company",
...@@ -112,7 +125,6 @@ const NON_BASE_FIELDS = [ ...@@ -112,7 +125,6 @@ const NON_BASE_FIELDS = [
"letterType", "letterType",
"manuscriptType", "manuscriptType",
"mapType", "mapType",
"nameOfAct",
"network", "network",
"patentNumber", "patentNumber",
"postType", "postType",
...@@ -124,20 +136,30 @@ const NON_BASE_FIELDS = [ ...@@ -124,20 +136,30 @@ const NON_BASE_FIELDS = [
"reportNumber", "reportNumber",
"reportType", "reportType",
"studio", "studio",
"subject",
"thesisType", "thesisType",
"university", "university",
"videoRecordingFormat", "videoRecordingFormat",
"websiteTitle", "websiteTitle",
"websiteType", "websiteType",
] as const; ] as const;
export type NonBaseField = typeof NON_BASE_FIELDS[number]; export type NonBaseRegularField = typeof NON_BASE_REGULAR_FIELDS[number];
// Base creator field key type type RegularField = BaseRegularField | NonBaseRegularField;
export type BaseCreatorField = BaseCreatorType;
export function isRegularField(field: unknown): field is RegularField {
return (
BASE_REGULAR_FIELDS.includes(field as BaseRegularField) ||
NON_BASE_REGULAR_FIELDS.includes(field as NonBaseRegularField)
);
}
// Non-base creator field key type // Creator field key types
export type BaseCreatorField = BaseCreatorType;
export type NonBaseCreatorField = NonBaseCreatorType; export type NonBaseCreatorField = NonBaseCreatorType;
type CreatorField = BaseCreatorField | NonBaseCreatorField;
export function isCreatorField(field: unknown): field is CreatorField {
return isCreatorType(field);
}
// Mediawiki field key type // Mediawiki field key type
const MEDIA_WIKI_ID_FIELDS = ["isbn", "issn", "PMCID", "PMID", "oclc"] as const; const MEDIA_WIKI_ID_FIELDS = ["isbn", "issn", "PMCID", "PMID", "oclc"] as const;
...@@ -147,13 +169,20 @@ const MEDIA_WIKI_FIELDS = [ ...@@ -147,13 +169,20 @@ const MEDIA_WIKI_FIELDS = [
"source", "source",
] as const; ] as const;
export type MediaWikiField = typeof MEDIA_WIKI_FIELDS[number]; export type MediaWikiField = typeof MEDIA_WIKI_FIELDS[number];
// export function isMediaWikiField(field: unknown): field is MediaWikiField {
// if (MEDIA_WIKI_FIELDS.includes(field as MediaWikiField)) {
// return true;
// } else {
// return false;
// }
// }
// Simple-citoid field key type // Simple-citoid field key type
const SIMPLE_CITOID_NON_CREATOR_FIELDS = [ const SIMPLE_CITOID_NON_CREATOR_FIELDS = [
...REQUIRED_FIELDS, ...REQUIRED_FIELDS,
...BASE_TITLE_FIELDS, ...BASE_TITLE_FIELDS,
"tags", "tags",
...BASE_FIELDS, ...BASE_REGULAR_FIELDS,
...MEDIA_WIKI_ID_FIELDS, ...MEDIA_WIKI_ID_FIELDS,
] as const; ] as const;
type SimpleCitoidNonCreatorField = type SimpleCitoidNonCreatorField =
...@@ -197,4 +226,148 @@ export function isSimpleCitoidField( ...@@ -197,4 +226,148 @@ export function isSimpleCitoidField(
} }
} }
// add non-base to base map // Base field map
export const baseFieldMap: Map<
| BaseTitleField
| NonBaseTitleField
| BaseRegularField
| NonBaseRegularField
| BaseCreatorField
| NonBaseCreatorField,
BaseTitleField | BaseRegularField | BaseCreatorField
> = new Map([
// https://docs.google.com/spreadsheets/d/1YcscX9krRtmSflOLKSa1FeVAfVzwZYo72Mev6h8yWOw/edit#gid=505421956
["title", "title"],
["abstractNote", "abstractNote"],
["artworkMedium", "medium"],
["artworkSize", "artworkSize"],
["date", "date"],
["language", "language"],
["shortTitle", "shortTitle"],
["archive", "archive"],
["archiveLocation", "archiveLocation"],
["libraryCatalog", "libraryCatalog"],
["callNumber", "callNumber"],
// ["url", "url"],
["accessDate", "accessDate"],
["rights", "rights"],
["extra", "extra"],
["audioRecordingFormat", "medium"],
["seriesTitle", "seriesTitle"],
["volume", "volume"],
["numberOfVolumes", "numberOfVolumes"],
["place", "place"],
["label", "publisher"],
["runningTime", "runningTime"],
// ["ISBN", "ISBN"],
["billNumber", "number"],
["code", "code"],
["codeVolume", "volume"],
["section", "section"],
["codePages", "pages"],
["legislativeBody", "legislativeBody"],
["session", "session"],
["history", "history"],
["blogTitle", "publicationTitle"],
["websiteType", "type"],
["series", "series"],