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 {
MediaWikiBaseFieldCitation,
MediaWikiCitation,
SimpleCitoidCitation,
} from "./citationTypes";
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(
mwbCitation: MediaWikiBaseFieldCitation
): SimpleCitoidCitation {
const simpleCitation: SimpleCitoidCitation = {
itemType: mwbCitation.itemType,
title: mwbCitation.title,
url: mwbCitation.url,
tags: mwbCitation.tags?.map((tag) => tag.tag),
};
// 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]
);
get mediawiki(): MediaWikiCitation {
return this.citation;
}
get mediawikibase(): MediaWikiBaseFieldCitation {
// fixme: consider improving implementation
const mwbCitation: MediaWikiBaseFieldCitation = {
// required
itemType: this.citation.itemType,
url: this.citation.url,
// title
title: (this.citation.title ||
this.citation.caseName ||
this.citation.subject ||
this.citation.nameOfAct)!,
// special
tags: this.citation.tags,
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 (
field in mwbCitation &&
!(field in simpleCitation) &&
field !== "itemType"
) {
const value = mwbCitation[field as keyof MediaWikiBaseFieldCitation] as
| string
| Array<string>;
simpleCitation[field] = value;
get simple(): SimpleCitoidCitation {
const mwbCitation = this.mediawikibase;
const simpleCitation: SimpleCitoidCitation = {
itemType: mwbCitation.itemType,
title: mwbCitation.title,
url: mwbCitation.url,
tags: mwbCitation.tags?.map((tag) => tag.tag),
};
// 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 {
RequiredFields,
BaseTitleFields,
NonBaseTitleFields,
TitleFields,
SpecialFields,
BaseFields,
NonBaseFields,
BaseRegularFields,
NonBaseRegularFields,
BaseCreatorFields,
NonBaseCreatorFields,
MediaWikiFields,
......@@ -16,11 +16,11 @@ import { REQUIRED_FIELDS, TITLE_FIELDS } from "./keyTypes";
// Citoid citation types
export type MediaWikiCitation = RequiredFields &
(BaseTitleFields | NonBaseTitleFields) &
TitleFields &
Partial<
SpecialFields &
BaseFields &
NonBaseFields &
BaseRegularFields &
NonBaseRegularFields &
BaseCreatorFields &
NonBaseCreatorFields &
MediaWikiFields
......@@ -28,11 +28,15 @@ export type MediaWikiCitation = RequiredFields &
export type MediaWikiBaseFieldCitation = RequiredFields &
BaseTitleFields &
Partial<SpecialFields & BaseFields & BaseCreatorFields & MediaWikiFields>;
Partial<
SpecialFields & BaseRegularFields & BaseCreatorFields & MediaWikiFields
>;
export type ZoteroCitation = RequiredFields &
(BaseTitleFields | NonBaseTitleFields) &
Partial<SpecialFields & BaseFields & NonBaseFields & ZoteroFields>;
type ZoteroCitation = RequiredFields &
TitleFields &
Partial<
SpecialFields & BaseRegularFields & NonBaseRegularFields & ZoteroFields
>;
export type CitoidCitation =
| MediaWikiCitation
......
// Creator types
////////////////
// Base creator field key type
// Base creator type
export const BASE_CREATOR_TYPES = [
"attorneyAgent",
"author",
......@@ -25,7 +25,7 @@ export const BASE_CREATOR_TYPES = [
] as const;
export type BaseCreatorType = typeof BASE_CREATOR_TYPES[number];
// Non-base creator field key type
// Non-base creator type
const NON_BASE_CREATOR_TYPES = [
"artist",
"cartographer",
......@@ -39,3 +39,13 @@ const NON_BASE_CREATOR_TYPES = [
"sponsor",
] as const;
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 {
BaseTitleField,
NonBaseTitleField,
SpecialField,
BaseField,
NonBaseField,
BaseRegularField,
NonBaseRegularField,
BaseCreatorField,
NonBaseCreatorField,
SplitBaseCreatorField,
......@@ -36,7 +36,7 @@ assert<Equals<RequiredField, keyof RequiredFields>>(true);
export type BaseTitleFields = {
[key in BaseTitleField]: string;
};
export type NonBaseTitleFields = OneKey<NonBaseTitleField, string>;
export type TitleFields = OneKey<BaseTitleField | NonBaseTitleField, string>;
// Special fields
export interface SpecialFields {
......@@ -47,10 +47,10 @@ export interface SpecialFields {
assert<Equals<SpecialField, keyof SpecialFields>>(true);
// Base fields
export type BaseFields = Record<BaseField, string>;
export type BaseRegularFields = Record<BaseRegularField, string>;
// Non-base fields
export type NonBaseFields = Record<NonBaseField, string>;
export type NonBaseRegularFields = Record<NonBaseRegularField, string>;
// Base creator fields
export type BaseCreatorFields = Record<
......@@ -93,7 +93,7 @@ export type SimpleCitoidFields = Record<
} & Partial<
Record<
| Exclude<SpecialField, "key" | "version">
| BaseField
| BaseRegularField
| SplitBaseCreatorField
| Exclude<MediaWikiField, "source">,
string | string[]
......
......@@ -2,11 +2,19 @@ import {
BaseCreatorType,
NonBaseCreatorType,
BASE_CREATOR_TYPES,
isCreatorType,
} from "./creatorTypes";
// Required field key type
export const REQUIRED_FIELDS = ["itemType", "url"] as const;
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
const BASE_TITLE_FIELDS = ["title"] as const;
......@@ -21,9 +29,16 @@ export const TITLE_FIELDS = [
// Special field key type
const SPECIAL_FIELDS = ["tags", "key", "version"] as const;
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
const BASE_FIELDS = [
// Regular field key types
const BASE_REGULAR_FIELDS = [
"abstractNote",
"accessDate",
"applicationNumber",
......@@ -79,10 +94,9 @@ const BASE_FIELDS = [
"versionNumber",
"volume",
] 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_FIELDS = [
const NON_BASE_REGULAR_FIELDS = [
// NO field is mapped to this field in ANY item type
"artworkMedium",
"audioFileType",
......@@ -90,7 +104,6 @@ const NON_BASE_FIELDS = [
"billNumber",
"blogTitle",
"bookTitle",
"caseName",
"codePages",
"codeVolume",
"company",
......@@ -112,7 +125,6 @@ const NON_BASE_FIELDS = [
"letterType",
"manuscriptType",
"mapType",
"nameOfAct",
"network",
"patentNumber",
"postType",
......@@ -124,20 +136,30 @@ const NON_BASE_FIELDS = [
"reportNumber",
"reportType",
"studio",
"subject",
"thesisType",
"university",
"videoRecordingFormat",
"websiteTitle",
"websiteType",
] as const;
export type NonBaseField = typeof NON_BASE_FIELDS[number];
export type NonBaseRegularField = typeof NON_BASE_REGULAR_FIELDS[number];
// Base creator field key type
export type BaseCreatorField = BaseCreatorType;
type RegularField = BaseRegularField | NonBaseRegularField;
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;
type CreatorField = BaseCreatorField | NonBaseCreatorField;
export function isCreatorField(field: unknown): field is CreatorField {
return isCreatorType(field);
}
// Mediawiki field key type
const MEDIA_WIKI_ID_FIELDS = ["isbn", "issn", "PMCID", "PMID", "oclc"] as const;
......@@ -147,13 +169,20 @@ const MEDIA_WIKI_FIELDS = [
"source",
] as const;
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
const SIMPLE_CITOID_NON_CREATOR_FIELDS = [
...REQUIRED_FIELDS,
...BASE_TITLE_FIELDS,
"tags",
...BASE_FIELDS,
...BASE_REGULAR_FIELDS,
...MEDIA_WIKI_ID_FIELDS,
] as const;
type SimpleCitoidNonCreatorField =
......@@ -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"],
["seriesNumber", "seriesNumber"],
["edition", "edition"],
["publisher", "publisher"],
["numPages", "numPages"],
["bookTitle", "publicationTitle"],
["pages", "pages"],
["caseName", "title"],
["court", "court"],
["dateDecided", "date"],
["docketNumber", "number"],
["reporter", "reporter"],
["reporterVolume", "volume"],
["firstPage", "pages"],
["versionNumber", "versionNumber"],
["system", "system"],
["company", "publisher"],
["programmingLanguage", "programmingLanguage"],
["proceedingsTitle", "publicationTitle"],
["conferenceName", "conferenceName"],
["DOI", "DOI"],
["dictionaryTitle", "publicationTitle"],
["subject", "title"],
["encyclopediaTitle", "publicationTitle"],
["distributor", "publisher"],
["genre", "type"],
["videoRecordingFormat", "medium"],
["forumTitle", "publicationTitle"],
["postType", "type"],
["committee", "committee"],
["documentNumber", "number"],
["interviewMedium", "medium"],
["publicationTitle", "publicationTitle"],
["issue", "issue"],
["seriesText", "seriesText"],
["journalAbbreviation", "journalAbbreviation"],
// ["ISSN", "ISSN"],
["letterType", "type"],
["manuscriptType", "type"],
["mapType", "type"],
["scale", "scale"],
["country", "country"],
["assignee", "assignee"],
["issuingAuthority", "issuingAuthority"],
["patentNumber", "number"],
["filingDate", "filingDate"],
["applicationNumber", "applicationNumber"],
["priorityNumbers", "priorityNumbers"],
["issueDate", "date"],
["references", "references"],
["legalStatus", "legalStatus"],
["episodeNumber", "number"],
["audioFileType", "medium"],
["presentationType", "type"],
["meetingName", "meetingName"],
["programTitle", "publicationTitle"],
["network", "publisher"],
["reportNumber", "number"],
["reportType", "type"],
["institution", "publisher"],
["nameOfAct", "title"],
["codeNumber", "codeNumber"],
["publicLawNumber", "number"],
["dateEnacted", "date"],
["thesisType", "type"],
["university", "publisher"],
["studio", "publisher"],
["websiteTitle", "publicationTitle"],
["medium", "medium"],
["type", "type"],
["number", "number"],
["author", "author"],
["contributor", "author"],
["editor", "editor"],
["seriesEditor", "seriesEditor"],
["translator", "translator"],
["bookAuthor", "bookAuthor"],
["reviewedAuthor", "reviewedAuthor"],
["recipient", "recipient"],
["interviewee", "author"],
["interviewer", "interviewer"],
["director", "author"],
["producer", "producer"],
["scriptwriter", "scriptwriter"],
["artist", "author"],
["sponsor", "author"],
["cosponsor", "cosponsor"],
["counsel", "counsel"],
["inventor", "author"],
["attorneyAgent", "attorneyAgent"],
["cartographer", "author"],
["commenter", "commenter"],
["performer", "author"],
["composer", "composer"],
["wordsBy", "wordsBy"],