diff --git a/packages/ts-etl/package.json b/packages/ts-etl/package.json index d337ea3a..496e5a55 100644 --- a/packages/ts-etl/package.json +++ b/packages/ts-etl/package.json @@ -25,10 +25,10 @@ "tsconfig.json" ], "dependencies": { - "commander": "^10.0.1", "@commander-js/extra-typings": "^10.0.3", + "commander": "^10.0.1", "crossref-openapi-client-ts": "^1.3.0", - "docmaps-sdk": "^0.5.0", + "docmaps-sdk": "^0.5.1", "fp-ts": "^2.14.0" }, "devDependencies": { diff --git a/packages/ts-etl/src/plugins/crossref/api.ts b/packages/ts-etl/src/plugins/crossref/api.ts index 1b04bd4a..ad4d09e9 100644 --- a/packages/ts-etl/src/plugins/crossref/api.ts +++ b/packages/ts-etl/src/plugins/crossref/api.ts @@ -7,7 +7,7 @@ import * as TE from 'fp-ts/lib/TaskEither' import * as D from 'docmaps-sdk' import { eqString } from 'fp-ts/lib/Eq' import { - leftToStrError, + mapLeftToUnknownError, decodeActionForWork, stepArrayToDocmap, thingForCrossrefWork, @@ -56,7 +56,7 @@ function stepsForDoiRecursive( }, ], })), - E.chain((action) => pipe(D.DocmapStep.decode(action), leftToStrError)), + E.chain((action) => pipe(D.DocmapStep.decode(action), mapLeftToUnknownError)), E.map((s) => ({ all: [s], head: s, @@ -133,7 +133,7 @@ function stepsForDoiRecursive( }, ], })), - TE.chainEitherK((rs) => leftToStrError(D.DocmapStep.decode(rs))), + TE.chainEitherK((rs) => mapLeftToUnknownError(D.DocmapStep.decode(rs))), TE.map((reviewStep) => ({ head: prefixChain.head, all: prefixChain.all.concat([reviewStep]), diff --git a/packages/ts-etl/src/plugins/crossref/functions.ts b/packages/ts-etl/src/plugins/crossref/functions.ts index 985df604..60e56790 100644 --- a/packages/ts-etl/src/plugins/crossref/functions.ts +++ b/packages/ts-etl/src/plugins/crossref/functions.ts @@ -25,7 +25,9 @@ function nameForAuthor(a: { family: string; name?: string; given?: string }): st export function decodeActionForWork(work: Work): E.Either { return pipe( E.Do, + // prepare the Thing which will be output E.bind('wo', () => pipe(work, thingForCrossrefWork, E.right)), + // prepare the Authors E.bind('wa', () => pipe( work.author || [], @@ -33,7 +35,7 @@ export function decodeActionForWork(work: Work): E.Either leftToStrError(D.DocmapActor.decode(a))), + E.traverseArray((a) => mapLeftToUnknownError(D.DocmapActor.decode(a))), E.map((auths) => auths.map((a) => ({ actor: a, @@ -42,6 +44,7 @@ export function decodeActionForWork(work: Work): E.Either pipe( { @@ -49,18 +52,30 @@ export function decodeActionForWork(work: Work): E.Either>>( (memo, next) => { if (E.isLeft(memo)) { @@ -116,29 +134,37 @@ export function stepArrayToDocmap( return E.right(m) }, + // initial memo: the first step only, whose next-step is inserted during + // the reduction loop and who doesn't need a first-step. since the reduce + // is creating an Either, we begin with an Either that never fails. E.right({ '_:b0': firstStep, }), ) - if (E.isLeft(reduction)) { - return reduction - } - const dmObject = D.Docmap.decode({ - ...dmBody, - 'first-step': '_:b0', - steps: reduction.right, - }) - - if (E.isLeft(dmObject)) { - return E.left(new Error('unable to parse manuscript step', { cause: dmObject.left })) - } - - return E.right([dmObject.right]) + return pipe( + reduction, + E.map((r) => ({ + ...dmBody, + 'first-step': '_:b0', + steps: r, + })), + E.chain((b) => pipe( + b, + D.Docmap.decode, + mapLeftToUnknownError, + )), + // requires to output Array of docmap + E.map((d) => [d]) + ) } -// FIXME this is a weak upcast - use t.Errors more effectively in ts-sdk -export const leftToStrError = E.mapLeft((e: unknown) => { +/** mapLeftToUnknownError - helper function for interoperating between Either types + * + * specifically, io-ts codecs are always of type Either, and that + * validation error is not naturally upcastable to Error where we use Either. + */ +export const mapLeftToUnknownError = E.mapLeft((e: unknown) => { if (e instanceof Error) { return e }