Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pub year volume #13

Merged
merged 12 commits into from
Jul 31, 2023
12 changes: 10 additions & 2 deletions examples/generated/04.reviewed_preprintv1.json
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,15 @@
"item": {
"type": "preprint",
"doi": "10.7554/eLife.80494.1",
"versionIdentifier": "1"
"versionIdentifier": "1",
"publicationYear": 2022,
"embodimentOf": {
"type": "manuscript",
"doi": "10.7554/eLife.80494",
"identifier": "80494",
"volumeIdentifier": "11",
"electronicArticleIdentifier": "RP80494"
}
},
"status": "manuscript-published",
"happened": "2022-10-20T00:00:00.000Z"
Expand Down Expand Up @@ -329,4 +337,4 @@
"previous-step": "_:b2"
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes should be removed or we should regenerate the the examples?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup

12 changes: 11 additions & 1 deletion src/docmap-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,23 @@ import {
Url,
VersionOfRecord,
WebPage,
Work,
} from './docmap';

type Steps = {
'first-step': string,
steps: Map<string, Step>
};

export const generatePreprint = (doi: DOI, published?: Date, url?: Url, version?: string, content?: Manifestation[], license?: string): Preprint => ({
export const generatePreprint = (doi: DOI, published?: Date, url?: Url, version?: string, content?: Manifestation[], license?: string, work?: Work): Preprint => ({
type: ExpressionType.Preprint,
doi,
url,
published,
versionIdentifier: version,
content,
license,
embodimentOf: work,
});

export const generateRevisedPreprint = (doi: DOI, published?: Date, url?: Url, version?: string, content?: Manifestation[]): RevisedPreprint => ({
Expand Down Expand Up @@ -112,6 +114,14 @@ export const generateWebContent = (url: Url): WebPage => ({
url,
});

export const generateWork = (doi?: DOI, identifier?: string, volumeIdentifier?: string, electronicArticleIdentifier?: string): Work => ({
type: 'manuscript',
doi,
identifier,
volumeIdentifier,
electronicArticleIdentifier,
});

export const generatePersonParticipant = (name: string, role: string): Participant => ({
actor: {
name,
Expand Down
19 changes: 19 additions & 0 deletions src/docmap-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,4 +385,23 @@ describe('docmap-parser', () => {
expect(parsedData.versions[0].preprint.license).toStrictEqual('http://creativecommons.org/licenses/by/4.0/');
expect(parsedData.versions[0].license).toStrictEqual('http://creativecommons.org/licenses/by/4.0/');
});

it('extracts embodimentOf, if present', () => {
const parsedData = parseDocMap(fixtures.preprintWithWorkAsOutput());

expect(parsedData.manuscript).toStrictEqual({
doi: '10.1101/123456',
volume: '1',
eLocationId: 'RP123456',
});
});

it('extracts partial embodimentOf, if present', () => {
const parsedData = parseDocMap(fixtures.preprintWithPartialWorkAsOutput());

expect(parsedData.manuscript).toStrictEqual({
doi: '10.1101/123456',
eLocationId: 'RP123456',
});
});
});
55 changes: 45 additions & 10 deletions src/docmap-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,30 @@ export type VersionedReviewedPreprint = ReviewedPreprint & {
versionIdentifier: string,
};

export type Manuscript = {
doi?: string,
volume?: string,
eLocationId?: string,
};

export type ManuscriptData = {
id: string,
manuscript?: Manuscript,
versions: VersionedReviewedPreprint[],
};

const getManuscriptFromExpression = (expression: Expression): Manuscript | false => {
if (!expression.embodimentOf) {
return false;
}

return {
doi: expression.embodimentOf.doi,
volume: expression.embodimentOf.volumeIdentifier,
eLocationId: expression.embodimentOf.electronicArticleIdentifier,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expression.embodimentOf.doi, expression.embodimentOf.doi and expression.embodimentOf.electronicArticleIdentifier are optional. We should expand the tests to account for this. This feels like it might fail or not return the expect value if one of the embodimentOf properties was not set.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did add a test to account for one of the props being empty. This resulted in a failing test, because it was retuning undefined for all props, so we expanded the updating of the manuscript data to only set values when the value is truthy. Is this what you wanted to cover? The values returned in this function are only used there, never directly returned to the calling user.

};
};

const getPreprintFromExpression = (expression: Expression): Preprint => {
if (!expression.doi) {
throw Error('Cannot identify Expression by DOI');
Expand Down Expand Up @@ -171,13 +190,27 @@ const addPreprintDescribedBy = (expression: Expression, preprintCollection: Arra
return newPreprint;
};

const findAndUpdateOrAddPreprintDescribedBy = (expression: Expression, preprintCollection: Array<ReviewedPreprint>): ReviewedPreprint => {
const findAndUpdateOrAddPreprintDescribedBy = (expression: Expression, preprintCollection: Array<ReviewedPreprint>, manuscript: Manuscript): ReviewedPreprint => {
const foundManuscriptData = getManuscriptFromExpression(expression);
const existingManuscript = manuscript;
if (foundManuscriptData) {
if (foundManuscriptData.doi) {
existingManuscript.doi = foundManuscriptData.doi;
}
if (foundManuscriptData.eLocationId) {
existingManuscript.eLocationId = foundManuscriptData.eLocationId;
}
if (foundManuscriptData.volume) {
existingManuscript.volume = foundManuscriptData.volume;
}
}
const foundPreprint = findPreprintDescribedBy(expression, preprintCollection);
if (!foundPreprint) {
return addPreprintDescribedBy(expression, preprintCollection);
}
// Update fields, default to any data already there.
updateReviewedPreprintFrom(foundPreprint, expression);

return foundPreprint;
};

Expand Down Expand Up @@ -314,36 +347,36 @@ const getAuthorResponse = (step: Step): { preprint: Item, authorResponse: Item }
return (authorResponseOutputs.length === 1 && items.preprintInputs.length === 1) ? { preprint: items.preprintInputs[0], authorResponse: authorResponseOutputs[0] } : false;
};

const parseStep = (step: Step, preprints: Array<ReviewedPreprint>): Array<ReviewedPreprint> => {
const parseStep = (step: Step, preprints: Array<ReviewedPreprint>, manuscript: Manuscript): Array<ReviewedPreprint> => {
const preprintPublishedAssertion = step.assertions.find((assertion) => assertion.status === AssertionStatus.Published);
if (preprintPublishedAssertion) {
// Update type and sent for review date
const preprint = findAndUpdateOrAddPreprintDescribedBy(preprintPublishedAssertion.item, preprints);
const preprint = findAndUpdateOrAddPreprintDescribedBy(preprintPublishedAssertion.item, preprints, manuscript);
preprint.publishedDate = preprintPublishedAssertion.happened ?? preprint.publishedDate;
}

const inferredPublished = getPublishedPreprint(step);
if (inferredPublished) {
findAndUpdateOrAddPreprintDescribedBy(inferredPublished, preprints);
findAndUpdateOrAddPreprintDescribedBy(inferredPublished, preprints, manuscript);
}

const preprintUnderReviewAssertion = step.assertions.find((assertion) => assertion.status === AssertionStatus.UnderReview);
if (preprintUnderReviewAssertion) {
// Update type and sent for review date
const preprint = findAndUpdateOrAddPreprintDescribedBy(preprintUnderReviewAssertion.item, preprints);
const preprint = findAndUpdateOrAddPreprintDescribedBy(preprintUnderReviewAssertion.item, preprints, manuscript);
preprint.sentForReviewDate = preprintUnderReviewAssertion.happened;
}

const inferredRepublished = getRepublishedPreprint(step);
if (inferredRepublished) {
// preprint input, preprint output, but no evaluations = superceed input preprint with output Reviewed Preprint
const preprint = findAndUpdateOrAddPreprintDescribedBy(inferredRepublished.originalExpression, preprints);
const preprint = findAndUpdateOrAddPreprintDescribedBy(inferredRepublished.originalExpression, preprints, manuscript);
republishPreprintAs(inferredRepublished.republishedExpression, preprint);
}

const inferredPeerReviewed = getPeerReviewedPreprint(step);
if (inferredPeerReviewed) {
const preprint = findAndUpdateOrAddPreprintDescribedBy(inferredPeerReviewed.peerReviewedPreprint, preprints);
const preprint = findAndUpdateOrAddPreprintDescribedBy(inferredPeerReviewed.peerReviewedPreprint, preprints, manuscript);
setPeerReviewFrom(step.actions, preprint);
preprint.reviewedDate = preprint.peerReview?.evaluationSummary?.date;

Expand All @@ -355,13 +388,13 @@ const parseStep = (step: Step, preprints: Array<ReviewedPreprint>): Array<Review

const newVersionPreprint = getNewVersionPreprint(step);
if (newVersionPreprint) {
findAndUpdateOrAddPreprintDescribedBy(newVersionPreprint.newVersionExpression, preprints);
findAndUpdateOrAddPreprintDescribedBy(newVersionPreprint.newVersionExpression, preprints, manuscript);
}

// sometimes author response is a separate step, find those and add the author response
const authorResponse = getAuthorResponse(step);
if (authorResponse) {
const preprint = findAndUpdateOrAddPreprintDescribedBy(authorResponse.preprint, preprints);
const preprint = findAndUpdateOrAddPreprintDescribedBy(authorResponse.preprint, preprints, manuscript);
setPeerReviewFrom(step.actions, preprint);
preprint.authorResponseDate = authorResponse.authorResponse.published;
}
Expand Down Expand Up @@ -430,8 +463,9 @@ export const parsePreprintDocMap = (docMap: DocMap | string): ManuscriptData =>
const stepsIterator = getSteps(docMapStruct);
let currentStep = stepsIterator.next().value;
let preprints: Array<ReviewedPreprint> = [];
const manuscript: Manuscript = {};
while (currentStep) {
preprints = parseStep(currentStep, preprints);
preprints = parseStep(currentStep, preprints, manuscript);
currentStep = stepsIterator.next().value;
}

Expand All @@ -442,6 +476,7 @@ export const parsePreprintDocMap = (docMap: DocMap | string): ManuscriptData =>
const { id, versions } = finaliseVersions(preprints);
return {
id,
manuscript,
versions,
};
};
9 changes: 9 additions & 0 deletions src/docmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export type Expression = {
doi?: DOI,
content?: Manifestation[],
license?: string,
embodimentOf?: Work,
};

export type Manifestation = {
Expand Down Expand Up @@ -115,6 +116,14 @@ export type Assertion = {
happened?: Date,
};

export type Work = {
type: 'manuscript',
doi?: DOI,
identifier?: string,
volumeIdentifier?: string,
electronicArticleIdentifier?: string,
};

export type Step = {
assertions: Assertion[],
inputs: Input[],
Expand Down
15 changes: 15 additions & 0 deletions src/test-fixtures/docmapGenerators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
generateStep,
generateUnderReviewAssertion,
generateWebContent,
generateWork,
} from '../docmap-generator';

const publisher = {
Expand Down Expand Up @@ -46,6 +47,20 @@ export const fixtures = {
return generateDocMap('test', publisher, firstStep);
},

preprintWithWorkAsOutput: (): DocMap => {
const work = generateWork('10.1101/123456', '123456', '1', 'RP123456');
const preprint = generatePreprint('preprint/article1', new Date('2022-03-01'), undefined, undefined, undefined, undefined, work);
const firstStep = generateStep([], [generateAction([], [preprint])], []);
return generateDocMap('test', publisher, firstStep);
},

preprintWithPartialWorkAsOutput: (): DocMap => {
const work = generateWork('10.1101/123456', '123456', undefined, 'RP123456');
const preprint = generatePreprint('preprint/article1', new Date('2022-03-01'), undefined, undefined, undefined, undefined, work);
const firstStep = generateStep([], [generateAction([], [preprint])], []);
return generateDocMap('test', publisher, firstStep);
},

simplePreprintWithUrlAsOutput: (): DocMap => {
const preprint = generatePreprint('preprint/article1', new Date('2022-03-01'), 'https://somewhere.org/preprint/article1');
const firstStep = generateStep([], [generateAction([], [preprint])], []);
Expand Down