diff --git a/shared-operations/src/compiletime/operatorDescription.ts b/shared-operations/src/compiletime/operatorDescription.ts index a831353f4..df12d6f35 100644 --- a/shared-operations/src/compiletime/operatorDescription.ts +++ b/shared-operations/src/compiletime/operatorDescription.ts @@ -18,11 +18,11 @@ import { if (isJsFile) { const baseName = path.basename(filePath, '.ts'); - if(baseName != "index") { + if(baseName != "index" && !baseName.endsWith(".schema")) { //TODO: Extract more info from operators. Currently not possible see: https://github.com/egoist/vite-plugin-compile-time/issues/25 jsFiles.push({ - baseName: baseName + basename: baseName }); } } diff --git a/shared-operations/src/functions/arrangePages.schema.ts b/shared-operations/src/functions/arrangePages.schema.ts new file mode 100644 index 000000000..050bdadfa --- /dev/null +++ b/shared-operations/src/functions/arrangePages.schema.ts @@ -0,0 +1,26 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "arrangePages" }), + i18next.t("description", { ns: "arrangePages" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + arrangementConfig: Joi.string().valid(...[ + "REVERSE_ORDER", + "DUPLEX_SORT", + "BOOKLET_SORT", + "SIDE_STITCH_BOOKLET_SORT", + "ODD_EVEN_SPLIT", + "REMOVE_FIRST", + "REMOVE_LAST", + "REMOVE_FIRST_AND_LAST" + ]).required() + .label(i18next.t("values.arrangementConfig.friendlyName", { ns: "arrangePages" })).description(i18next.t("values.arrangementConfig.description", { ns: "arrangePages" })) + .example("REVERSE_ORDER").example("DUPLEX_SORT").example("BOOKLET_SORT").required() + }), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/arrangePages.ts b/shared-operations/src/functions/arrangePages.ts index edbbb3349..be3ffe5d0 100644 --- a/shared-operations/src/functions/arrangePages.ts +++ b/shared-operations/src/functions/arrangePages.ts @@ -1,49 +1,10 @@ import { Operator, Progress, oneToOne } from "."; -import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - import { PdfFile } from "../wrappers/PdfFile"; import { Sorts } from "./common/pageIndexesSorting"; import { getPages } from "./common/getPagesByIndex"; export class ArrangePages extends Operator { - static type = "arrangePages"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - arrangementConfig: Joi.string().valid(...[ - "REVERSE_ORDER", - "DUPLEX_SORT", - "BOOKLET_SORT", - "SIDE_STITCH_BOOKLET_SORT", - "ODD_EVEN_SPLIT", - "REMOVE_FIRST", - "REMOVE_LAST", - "REMOVE_FIRST_AND_LAST" - ]).required() - .label(i18next.t("values.arrangementConfig.friendlyName", { ns: "arrangePages" })).description(i18next.t("values.arrangementConfig.description", { ns: "arrangePages" })) - .example("REVERSE_ORDER").example("DUPLEX_SORT").example("BOOKLET_SORT").required() - }); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: ArrangePages.inputSchema, - values: ArrangePages.valueSchema.required(), - output: ArrangePages.outputSchema - }).label(i18next.t("friendlyName", { ns: "arrangePages" })).description(i18next.t("description", { ns: "arrangePages" })); - - - /** - * Logic - */ - /** Detect and remove white pages */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/extractPages.schema.ts b/shared-operations/src/functions/extractPages.schema.ts new file mode 100644 index 000000000..a8735f7fd --- /dev/null +++ b/shared-operations/src/functions/extractPages.schema.ts @@ -0,0 +1,19 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "extractPages" }), + i18next.t("description", { ns: "extractPages" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + pageIndexes: CommaArrayJoiExt.comma_array().items(Joi.number().integer()).required() + .label(i18next.t("values.pageIndexes.friendlyName", { ns: "extractPages" })).description(i18next.t("values.pageIndexes.description", { ns: "extractPages" })) + .example("1").example("1, 2, 3, 4").example("4, 2, 4, 3").required() + }), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/extractPages.ts b/shared-operations/src/functions/extractPages.ts index 6bbbb650d..3d8c57ae2 100644 --- a/shared-operations/src/functions/extractPages.ts +++ b/shared-operations/src/functions/extractPages.ts @@ -1,40 +1,8 @@ -import { PdfFile, RepresentationType } from "../wrappers/PdfFile"; +import { PdfFile } from "../wrappers/PdfFile"; import { Operator, Progress, oneToOne } from "."; - -import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - import { getPages } from "./common/getPagesByIndex"; -import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; export class ExtractPages extends Operator { - static type = "extractPages"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - pageIndexes: CommaArrayJoiExt.comma_array().items(Joi.number().integer()).required() - .label(i18next.t("values.pageIndexes.friendlyName", { ns: "extractPages" })).description(i18next.t("values.pageIndexes.description", { ns: "extractPages" })) - .example("1").example("1, 2, 3, 4").example("4, 2, 4, 3").required() - }); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: ExtractPages.inputSchema, - values: ExtractPages.valueSchema.required(), - output: ExtractPages.outputSchema - }).label(i18next.t("friendlyName", { ns: "extractPages" })).description(i18next.t("description", { ns: "extractPages" })); - - - /** - * Logic - */ - /** PDF extraction, specify pages from one pdf and output them to a new pdf */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/impose.ts b/shared-operations/src/functions/impose.ts index 420b81ceb..15ecf71b8 100644 --- a/shared-operations/src/functions/impose.ts +++ b/shared-operations/src/functions/impose.ts @@ -5,10 +5,6 @@ import { Operator, Progress, oneToOne } from "."; import * as pdfcpuWrapper from "#pdfcpu"; // This is updated by tsconfig.json/paths for the context (browser, node, etc.) this module is used in. export class Impose extends Operator { - /** - * Logic - */ - /** PDF-Imposition, PDF-N-Up: Put multiple pages of the input document into a single page of the output document. - see: {@link https://en.wikipedia.org/wiki/N-up} */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/merge.schema.ts b/shared-operations/src/functions/merge.schema.ts new file mode 100644 index 000000000..ecb721856 --- /dev/null +++ b/shared-operations/src/functions/merge.schema.ts @@ -0,0 +1,13 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "merge" }), + i18next.t("description", { ns: "merge" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({}), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/merge.ts b/shared-operations/src/functions/merge.ts index 0bce193d7..245f458d2 100644 --- a/shared-operations/src/functions/merge.ts +++ b/shared-operations/src/functions/merge.ts @@ -2,35 +2,9 @@ import { PdfFile, RepresentationType } from "../wrappers/PdfFile"; import { Operator, Progress, nToOne } from "."; -import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - import { PDFDocument } from "pdf-lib"; export class Merge extends Operator { - static type = "merge"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({}); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: Merge.inputSchema, - values: Merge.valueSchema.required(), - output: Merge.outputSchema - }).label(i18next.t("friendlyName", { ns: "merge" })).description(i18next.t("description", { ns: "merge" })); - - - /** - * Logic - */ - /** Merging pages from multiple pdfs into a singe output document. */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return nToOne(input, async (input) => { diff --git a/shared-operations/src/functions/removeBlankPages.schema.ts b/shared-operations/src/functions/removeBlankPages.schema.ts new file mode 100644 index 000000000..a36b15f52 --- /dev/null +++ b/shared-operations/src/functions/removeBlankPages.schema.ts @@ -0,0 +1,17 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "removeBlankPages" }), + i18next.t("description", { ns: "removeBlankPages" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + whiteThreashold: Joi.number().min(0).max(255).required() + .label(i18next.t("values.whiteThreashold.friendlyName", { ns: "removeBlankPages" })).description(i18next.t("values.whiteThreashold.description", { ns: "removeBlankPages" })) + .example("10").example("0").example("255").required() + }), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/removeBlankPages.ts b/shared-operations/src/functions/removeBlankPages.ts index 577c556f1..a391542b3 100644 --- a/shared-operations/src/functions/removeBlankPages.ts +++ b/shared-operations/src/functions/removeBlankPages.ts @@ -1,41 +1,11 @@ import { Operator, Progress, oneToOne } from "."; -import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - import { PdfFile } from "../wrappers/PdfFile"; import { detectEmptyPages } from "./common/detectEmptyPages"; import { getPages } from "./common/getPagesByIndex"; import { invertSelection } from "./common/pageIndexesUtils"; export class RemoveBlankPages extends Operator { - static type = "removeBlankPages"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - whiteThreashold: Joi.number().min(0).max(255).required() - .label(i18next.t("values.whiteThreashold.friendlyName", { ns: "removeBlankPages" })).description(i18next.t("values.whiteThreashold.description", { ns: "removeBlankPages" })) - .example("10").example("0").example("255").required() - }); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: RemoveBlankPages.inputSchema, - values: RemoveBlankPages.valueSchema.required(), - output: RemoveBlankPages.outputSchema - }).label(i18next.t("friendlyName", { ns: "removeBlankPages" })).description(i18next.t("description", { ns: "removeBlankPages" })); - - - /** - * Logic - */ - /** Detect and remove white pages */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/removePages.schema.ts b/shared-operations/src/functions/removePages.schema.ts new file mode 100644 index 000000000..f7a419ed8 --- /dev/null +++ b/shared-operations/src/functions/removePages.schema.ts @@ -0,0 +1,19 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "removePages" }), + i18next.t("description", { ns: "removePages" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + pageIndexes: CommaArrayJoiExt.comma_array().items(Joi.number().integer()).required() + .label(i18next.t("values.pageIndexes.friendlyName", { ns: "removePages" })).description(i18next.t("values.pageIndexes.description", { ns: "removePages" })) + .example("1").example("1, 2, 3, 4").example("4, 2, 4, 3").required() + }), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/removePages.ts b/shared-operations/src/functions/removePages.ts index a70fe29fc..88964f16e 100644 --- a/shared-operations/src/functions/removePages.ts +++ b/shared-operations/src/functions/removePages.ts @@ -1,42 +1,10 @@ import { PdfFile } from "../wrappers/PdfFile"; import { Operator, Progress, oneToOne } from "."; - -import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - import { getPages } from "./common/getPagesByIndex"; -import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; import { invertSelection } from "./common/pageIndexesUtils"; export class RemovePages extends Operator { - static type = "removePages"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - pageIndexes: CommaArrayJoiExt.comma_array().items(Joi.number().integer()).required() - .label(i18next.t("values.pageIndexes.friendlyName", { ns: "removePages" })).description(i18next.t("values.pageIndexes.description", { ns: "removePages" })) - .example("1").example("1, 2, 3, 4").example("4, 2, 4, 3").required() - }); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: RemovePages.inputSchema, - values: RemovePages.valueSchema.required(), - output: RemovePages.outputSchema - }).label(i18next.t("friendlyName", { ns: "removePages" })).description(i18next.t("description", { ns: "removePages" })); - - - /** - * Logic - */ - /** PDF extraction, specify pages from one pdf and output them to a new pdf */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/rotatePages.schema.ts b/shared-operations/src/functions/rotatePages.schema.ts new file mode 100644 index 000000000..db545d7cf --- /dev/null +++ b/shared-operations/src/functions/rotatePages.schema.ts @@ -0,0 +1,22 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "rotatePages" }), + i18next.t("description", { ns: "rotatePages" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + rotation: Joi.alternatives().try( + Joi.number().integer().min(-360).max(360).required(), + CommaArrayJoiExt.comma_array().items(Joi.number().integer().min(-360).max(360)).required() + ) + .label(i18next.t("values.rotation.friendlyName", { ns: "rotatePages" })).description(i18next.t("values.rotation.description", { ns: "rotatePages" })) + .example("90").example("-180").example("[90, 0, 270]"), + }), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/rotatePages.ts b/shared-operations/src/functions/rotatePages.ts index 0288f1f17..9a6b42d7a 100644 --- a/shared-operations/src/functions/rotatePages.ts +++ b/shared-operations/src/functions/rotatePages.ts @@ -1,44 +1,9 @@ import { Operator, Progress, oneToOne } from "."; -import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - -import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; - import { degrees } from "pdf-lib"; import { PdfFile, RepresentationType } from "../wrappers/PdfFile"; export class RotatePages extends Operator { - static type = "rotatePages"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - rotation: Joi.alternatives().try( - Joi.number().integer().min(-360).max(360).required(), - CommaArrayJoiExt.comma_array().items(Joi.number().integer().min(-360).max(360)).required() - ) - .label(i18next.t("values.rotation.friendlyName", { ns: "rotatePages" })).description(i18next.t("values.rotation.description", { ns: "rotatePages" })) - .example("90").example("-180").example("[90, 0, 270]"), - }); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: RotatePages.inputSchema, - values: RotatePages.valueSchema.required(), - output: RotatePages.outputSchema - }).label(i18next.t("friendlyName", { ns: "rotatePages" })).description(i18next.t("description", { ns: "rotatePages" })); - - - /** - * Logic - */ - /** Detect and remove white pages */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/scaleContent.schema.ts b/shared-operations/src/functions/scaleContent.schema.ts new file mode 100644 index 000000000..1a20d5ada --- /dev/null +++ b/shared-operations/src/functions/scaleContent.schema.ts @@ -0,0 +1,22 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "scaleContent" }), + i18next.t("description", { ns: "scaleContent" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + scaleFactor: Joi.alternatives().try( + Joi.number().required(), + CommaArrayJoiExt.comma_array().items(Joi.number()).required() + ) + .label(i18next.t("values.scaleFactor.friendlyName", { ns: "scaleContent" })).description(i18next.t("values.scaleFactor.description", { ns: "scaleContent" })) + .example("2").example("1.5").example("[1, 1.5, 0.9]"), + }), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/scaleContent.ts b/shared-operations/src/functions/scaleContent.ts index c919227dc..d0cf2df82 100644 --- a/shared-operations/src/functions/scaleContent.ts +++ b/shared-operations/src/functions/scaleContent.ts @@ -1,44 +1,9 @@ import { Operator, Progress, oneToOne } from "."; -import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - -import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; - import { PDFPage } from "pdf-lib"; import { PdfFile, RepresentationType } from "../wrappers/PdfFile"; export class ScaleContent extends Operator { - static type = "scaleContent"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - scaleFactor: Joi.alternatives().try( - Joi.number().required(), - CommaArrayJoiExt.comma_array().items(Joi.number()).required() - ) - .label(i18next.t("values.scaleFactor.friendlyName", { ns: "scaleContent" })).description(i18next.t("values.scaleFactor.description", { ns: "scaleContent" })) - .example("2").example("1.5").example("[1, 1.5, 0.9]"), - }); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: ScaleContent.inputSchema, - values: ScaleContent.valueSchema.required(), - output: ScaleContent.outputSchema - }).label(i18next.t("friendlyName", { ns: "scaleContent" })).description(i18next.t("description", { ns: "scaleContent" })); - - - /** - * Logic - */ - /** Detect and remove white pages */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/scalePage.schema.ts b/shared-operations/src/functions/scalePage.schema.ts new file mode 100644 index 000000000..d4390d7f7 --- /dev/null +++ b/shared-operations/src/functions/scalePage.schema.ts @@ -0,0 +1,20 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "scalePage" }), + i18next.t("description", { ns: "scalePage" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + height: Joi.number().min(0) + .label(i18next.t("values.height.friendlyName", { ns: "scalePage" })).description(i18next.t("values.height.description", { ns: "scalePage" })) + .example("842").example("595").example("1190"), + width: Joi.number().min(0) + .label(i18next.t("values.width.friendlyName", { ns: "scalePage" })).description(i18next.t("values.width.description", { ns: "scalePage" })) + .example("595").example("420").example("842"), + }).or("height", "width"), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/scalePage.ts b/shared-operations/src/functions/scalePage.ts index 741b6ad0e..904ad875b 100644 --- a/shared-operations/src/functions/scalePage.ts +++ b/shared-operations/src/functions/scalePage.ts @@ -1,42 +1,9 @@ import { Operator, Progress, oneToOne } from "."; -import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - import { PDFPage } from "pdf-lib"; import { PdfFile, RepresentationType } from "../wrappers/PdfFile"; export class ScalePage extends Operator { - static type = "scalePage"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - height: Joi.number().min(0) - .label(i18next.t("values.height.friendlyName", { ns: "scalePage" })).description(i18next.t("values.height.description", { ns: "scalePage" })) - .example("842").example("595").example("1190"), - width: Joi.number().min(0) - .label(i18next.t("values.width.friendlyName", { ns: "scalePage" })).description(i18next.t("values.width.description", { ns: "scalePage" })) - .example("595").example("420").example("842"), - }).or("height", "width"); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: ScalePage.inputSchema, - values: ScalePage.valueSchema.required(), - output: ScalePage.outputSchema - }).label(i18next.t("friendlyName", { ns: "scalePage" })).description(i18next.t("description", { ns: "scalePage" })); - - - /** - * Logic - */ - /** Detect and remove white pages */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/splitPagesByPreset.schema.ts b/shared-operations/src/functions/splitPagesByPreset.schema.ts new file mode 100644 index 000000000..2af8348e1 --- /dev/null +++ b/shared-operations/src/functions/splitPagesByPreset.schema.ts @@ -0,0 +1,26 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "splitPagesByPreset" }), + i18next.t("description", { ns: "splitPagesByPreset" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.alternatives().try( + Joi.object({ + type: Joi.string().valid("BAR_CODE").required() + }), + Joi.object({ + type: Joi.string().valid("QR_CODE").required() + }), + Joi.object({ + type: Joi.string().valid("BLANK_PAGE").required(), + whiteThreashold: Joi.number().min(0).max(255).required() + }), + ) + .label(i18next.t("values.splitSettings.friendlyName", { ns: "splitPagesByPreset" })).description(i18next.t("values.splitSettings.description", { ns: "splitPagesByPreset" }) + ), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/splitPagesByPreset.ts b/shared-operations/src/functions/splitPagesByPreset.ts index e726d5a70..0e7fd3343 100644 --- a/shared-operations/src/functions/splitPagesByPreset.ts +++ b/shared-operations/src/functions/splitPagesByPreset.ts @@ -13,40 +13,6 @@ import { detectQRCodePages } from "./common/detectQRCodePages"; export class SplitPagesByPreset extends Operator { - static type = "splitPagesByPreset"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.alternatives().try( - Joi.object({ - type: Joi.string().valid("BAR_CODE").required() - }), - Joi.object({ - type: Joi.string().valid("QR_CODE").required() - }), - Joi.object({ - type: Joi.string().valid("BLANK_PAGE").required(), - whiteThreashold: Joi.number().min(0).max(255).required() - }), - ) - .label(i18next.t("values.splitSettings.friendlyName", { ns: "splitPagesByPreset" })).description(i18next.t("values.splitSettings.description", { ns: "splitPagesByPreset" }) - ); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: SplitPagesByPreset.inputSchema, - values: SplitPagesByPreset.valueSchema.required(), - output: SplitPagesByPreset.outputSchema - }).label(i18next.t("friendlyName", { ns: "splitPagesByPreset" })).description(i18next.t("description", { ns: "splitPagesByPreset" })); - - - /** - * Logic - */ - /** Detect and remove white pages */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToN(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/splitPdfByIndex.schema.ts b/shared-operations/src/functions/splitPdfByIndex.schema.ts new file mode 100644 index 000000000..d1e363dba --- /dev/null +++ b/shared-operations/src/functions/splitPdfByIndex.schema.ts @@ -0,0 +1,19 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "splitPdfByIndex" }), + i18next.t("description", { ns: "splitPdfByIndex" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + pageIndexes: CommaArrayJoiExt.comma_array().items(Joi.number().integer()).required() + .label(i18next.t("values.pageIndexes.friendlyName", { ns: "splitPdfByIndex" })).description(i18next.t("values.pageIndexes.description", { ns: "splitPdfByIndex" })) + .example("1").example("1, 2, 3, 4").example("4, 2, 4, 3") + }), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/splitPdfByIndex.ts b/shared-operations/src/functions/splitPdfByIndex.ts index 848e65752..23d31c311 100644 --- a/shared-operations/src/functions/splitPdfByIndex.ts +++ b/shared-operations/src/functions/splitPdfByIndex.ts @@ -2,40 +2,10 @@ import { PdfFile } from "../wrappers/PdfFile"; import { Operator, Progress, oneToN } from "."; import Joi from "@stirling-tools/joi"; -import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; - -import i18next from "i18next"; - -import CommaArrayJoiExt from "../wrappers/CommaArrayJoiExt"; import { splitPagesByIndex } from "./common/splitPagesByIndex"; export class SplitPdfByIndex extends Operator { - static type = "splitPdfByIndex"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - pageIndexes: CommaArrayJoiExt.comma_array().items(Joi.number().integer()).required() - .label(i18next.t("values.pageIndexes.friendlyName", { ns: "splitPdfByIndex" })).description(i18next.t("values.pageIndexes.description", { ns: "splitPdfByIndex" })) - .example("1").example("1, 2, 3, 4").example("4, 2, 4, 3") - }); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: SplitPdfByIndex.inputSchema, - values: SplitPdfByIndex.valueSchema.required(), - output: SplitPdfByIndex.outputSchema - }).label(i18next.t("friendlyName", { ns: "splitPdfByIndex" })).description(i18next.t("description", { ns: "splitPdfByIndex" })); - - - /** - * Logic - */ - /** PDF extraction, specify pages from one pdf and output them to a new pdf */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToN(input, async (input, index, max) => { diff --git a/shared-operations/src/functions/updateMetadata.schema.ts b/shared-operations/src/functions/updateMetadata.schema.ts new file mode 100644 index 000000000..e561d3494 --- /dev/null +++ b/shared-operations/src/functions/updateMetadata.schema.ts @@ -0,0 +1,45 @@ +import { OperatorSchema } from "."; +import Joi from "@stirling-tools/joi"; +import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; + +import i18next from "i18next"; + +export default new OperatorSchema( + i18next.t("friendlyName", { ns: "updateMetadata" }), + i18next.t("description", { ns: "updateMetadata" }), + JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")), + Joi.object({ + deleteAll: Joi.boolean().invalid(false) + .label(i18next.t("values.deleteAll.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.deleteAll.description", { ns: "updateMetadata" })) + .example("true").example("false"), + author: Joi.string().optional().allow('') + .label(i18next.t("values.author.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.author.description", { ns: "updateMetadata" })) + .example("John Doe").example("Anthony Stirling"), // The author of the document + creationDate: Joi.date().allow("").allow(null) + .label(i18next.t("values.creationDate.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.creationDate.description", { ns: "updateMetadata" })) + .example("YYYY-MM-DD").example("2023-01-27"), // The creation date of the document (format: yyyy/MM/dd HH:mm:ss) + creator: Joi.string().optional().allow('') + .label(i18next.t("values.creator.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.creator.description", { ns: "updateMetadata" })) + .example("John Doe").example("Anthony Stirling"), // The creator of the document + keywords: Joi.string().optional().allow('') + .label(i18next.t("values.keywords.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.keywords.description", { ns: "updateMetadata" })) + .example("General").example("finances, leisure").example("finances leisure"), // The keywords for the document + modificationDate: Joi.date().allow("").allow(null) + .label(i18next.t("values.modificationDate.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.modificationDate.description", { ns: "updateMetadata" })) + .example("YYYY-MM-DD").example("2023-01-27"), // The modification date of the document (format: yyyy/MM/dd HH:mm:ss) + producer: Joi.string().optional().allow('') + .label(i18next.t("values.producer.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.producer.description", { ns: "updateMetadata" })) + .example("John Doe").example("Anthony Stirling"), // The producer of the document + subject: Joi.string().optional().allow('') + .label(i18next.t("values.subject.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.subject.description", { ns: "updateMetadata" })) + .example("Subject").example("This is an example Subject."), // The subject of the document + title: Joi.string().optional().allow('') + .label(i18next.t("values.title.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.title.description", { ns: "updateMetadata" })) + .example("Title").example("This is an example title."), // The title of the document + + // TODO: trapped?: string, // The trapped status of the document + + // TODO: allRequestParams?: {[key: string]: [key: string]}, // Map list of key and value of custom parameters. Note these must start with customKey and customValue if they are non-standard + }), + JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")) +); \ No newline at end of file diff --git a/shared-operations/src/functions/updateMetadata.ts b/shared-operations/src/functions/updateMetadata.ts index fb98f6d3d..a5400dec9 100644 --- a/shared-operations/src/functions/updateMetadata.ts +++ b/shared-operations/src/functions/updateMetadata.ts @@ -8,59 +8,6 @@ import { JoiPDFFileSchema } from "../wrappers/PdfFileJoi"; import i18next from "i18next"; export class UpdateMetadata extends Operator { - static type = "updateMetadata"; - - /** - * Validation & Localisation - */ - - protected static inputSchema = JoiPDFFileSchema.label(i18next.t("inputs.pdffile.name")).description(i18next.t("inputs.pdffile.description")); - protected static valueSchema = Joi.object({ - deleteAll: Joi.boolean().invalid(false) - .label(i18next.t("values.deleteAll.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.deleteAll.description", { ns: "updateMetadata" })) - .example("true").example("false"), - author: Joi.string().optional().allow('') - .label(i18next.t("values.author.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.author.description", { ns: "updateMetadata" })) - .example("John Doe").example("Anthony Stirling"), // The author of the document - creationDate: Joi.date().allow("").allow(null) - .label(i18next.t("values.creationDate.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.creationDate.description", { ns: "updateMetadata" })) - .example("YYYY-MM-DD").example("2023-01-27"), // The creation date of the document (format: yyyy/MM/dd HH:mm:ss) - creator: Joi.string().optional().allow('') - .label(i18next.t("values.creator.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.creator.description", { ns: "updateMetadata" })) - .example("John Doe").example("Anthony Stirling"), // The creator of the document - keywords: Joi.string().optional().allow('') - .label(i18next.t("values.keywords.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.keywords.description", { ns: "updateMetadata" })) - .example("General").example("finances, leisure").example("finances leisure"), // The keywords for the document - modificationDate: Joi.date().allow("").allow(null) - .label(i18next.t("values.modificationDate.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.modificationDate.description", { ns: "updateMetadata" })) - .example("YYYY-MM-DD").example("2023-01-27"), // The modification date of the document (format: yyyy/MM/dd HH:mm:ss) - producer: Joi.string().optional().allow('') - .label(i18next.t("values.producer.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.producer.description", { ns: "updateMetadata" })) - .example("John Doe").example("Anthony Stirling"), // The producer of the document - subject: Joi.string().optional().allow('') - .label(i18next.t("values.subject.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.subject.description", { ns: "updateMetadata" })) - .example("Subject").example("This is an example Subject."), // The subject of the document - title: Joi.string().optional().allow('') - .label(i18next.t("values.title.friendlyName", { ns: "updateMetadata" })).description(i18next.t("values.title.description", { ns: "updateMetadata" })) - .example("Title").example("This is an example title."), // The title of the document - - // TODO: trapped?: string, // The trapped status of the document - - // TODO: allRequestParams?: {[key: string]: [key: string]}, // Map list of key and value of custom parameters. Note these must start with customKey and customValue if they are non-standard - }); - protected static outputSchema = JoiPDFFileSchema.label(i18next.t("outputs.pdffile.name")).description(i18next.t("outputs.pdffile.description")); - - static schema = Joi.object({ - input: UpdateMetadata.inputSchema, - values: UpdateMetadata.valueSchema.required(), - output: UpdateMetadata.outputSchema - }).label(i18next.t("friendlyName", { ns: "updateMetadata" })).description(i18next.t("description", { ns: "updateMetadata" })); - - - /** - * Logic - */ - /** PDF extraction, specify pages from one pdf and output them to a new pdf */ async run(input: PdfFile[], progressCallback: (state: Progress) => void): Promise { return oneToOne(input, async (input, index, max) => { diff --git a/shared-operations/src/workflow/operatorAccessor.ts b/shared-operations/src/workflow/operatorAccessor.ts index 9729a9287..9c630f230 100644 --- a/shared-operations/src/workflow/operatorAccessor.ts +++ b/shared-operations/src/workflow/operatorAccessor.ts @@ -1,4 +1,4 @@ -import { Operator } from "../functions"; +import { Operator, OperatorSchema } from "../functions"; import i18next from "i18next"; const compileTimeOperatorList: {basename: string}[] = import.meta.compileTime("../compiletime/operatorDescription.ts"); // The will compile to ["impose", "extractPages", etc...] @@ -7,7 +7,6 @@ export async function getOperatorByName(name: string): Promise e.basename == name)) return; - i18next.loadNamespaces(name, (err, t) => { if (err) throw err; console.log(t) }); const loadedModule = await import("../functions/" + name + ".ts"); const operator = loadedModule[capitalizeFirstLetter(name)]; if(!operator) { @@ -16,6 +15,19 @@ export async function getOperatorByName(name: string): Promise { + // Check if exists + if(!compileTimeOperatorList.find(e => e.basename == name)) return; + + i18next.loadNamespaces(name, (err, t) => { if (err) throw err; console.log(t) }); + const loadedModule = await import("../functions/" + name + ".schema.ts"); + const schema = loadedModule.default; + if(!schema) { + throw Error("This operator does not export its class in the correct format.") + } + return schema; +} + export function listOperatorNames(): string[] { const availableOperators = compileTimeOperatorList.map(e => e.basename); return availableOperators; diff --git a/shared-operations/src/workflow/organizeWaitOperations.ts b/shared-operations/src/workflow/organizeWaitOperations.ts index 3fe9b519e..f8bde00cb 100644 --- a/shared-operations/src/workflow/organizeWaitOperations.ts +++ b/shared-operations/src/workflow/organizeWaitOperations.ts @@ -44,7 +44,7 @@ export function organizeWaitOperations(actions: Action[]) { } export type ResultType = Record; \ No newline at end of file + waitCount: number, + doneOperation: Action, + input: PdfFile[] +}>; \ No newline at end of file diff --git a/shared-operations/src/workflow/validateOperations.ts b/shared-operations/src/workflow/validateOperations.ts index da036a401..1faf70ba3 100644 --- a/shared-operations/src/workflow/validateOperations.ts +++ b/shared-operations/src/workflow/validateOperations.ts @@ -1,6 +1,6 @@ -import { Operator } from "../functions"; +import { OperatorSchema } from "../functions"; import { Action } from "../../declarations/Action"; -import { getOperatorByName } from "./operatorAccessor"; +import { getOperatorByName, getSchemaByName } from "./operatorAccessor"; /** This function validates the "workflow-json" from the API */ export async function validateOperations(actions: Action[]): Promise<{ valid: boolean, reason?: string}> { @@ -18,7 +18,11 @@ export async function validateOperations(actions: Action[]): Promise<{ valid: bo if(!operator) { return { valid: false, reason: `action.type ${action.type} does not exist` }; } - const validationResult = operator.schema.validate({values: action.values}); + const schema = await getSchemaByName(action.type); + if(!operator) { + return { valid: false, reason: `action.type ${action.type} does not exist` }; + } + const validationResult = schema.schema.validate({values: action.values}); // TODO: convert everything to joiresult format instead of returning a new format if(validationResult.error) { @@ -35,10 +39,10 @@ export async function validateOperations(actions: Action[]): Promise<{ valid: bo } for (const afterDoneChild of done[childAction.values.id]?.actions || []) { - const receivingOperator = await getOperatorByName(afterDoneChild.type); - if (receivingOperator === undefined) { + const receivingSchema = await getSchemaByName(afterDoneChild.type); + if (receivingSchema === undefined) { return { valid: false, reason: `action.type ${afterDoneChild.type} does not exist.` }; - } else if (!ioCompatible(operator, receivingOperator)) { + } else if (!ioCompatible(schema, receivingSchema)) { return { valid: false, reason: `Ouput of action ${action.type} is not compatible with input of action ${afterDoneChild.type}` }; } } @@ -47,10 +51,10 @@ export async function validateOperations(actions: Action[]): Promise<{ valid: bo return { valid: false, reason: "There shouldn't be a done action here." }; } else { - const receivingOperator = await getOperatorByName(childAction.type); - if (receivingOperator === undefined) { + const receivingSchema = await getSchemaByName(childAction.type); + if (receivingSchema === undefined) { return { valid: false, reason: `action.type ${childAction.type} does not exist.` }; - } else if (!ioCompatible(operator, receivingOperator)) { + } else if (!ioCompatible(schema, receivingSchema)) { return { valid: false, reason: `Ouput of action ${action.type} is not compatible with input of action ${childAction.type}` }; } } @@ -66,8 +70,8 @@ export async function validateOperations(actions: Action[]): Promise<{ valid: bo return { valid: true }; } -function ioCompatible(outputingOperator: typeof Operator, receivingOperator: typeof Operator): boolean { - const outputType = outputingOperator.schema.describe().keys.output.label; - const inputType = receivingOperator.schema.describe().keys.input.label; +function ioCompatible(outputingSchema: OperatorSchema, receivingSchema: OperatorSchema): boolean { + const outputType = outputingSchema.schema.describe().keys.output.label; + const inputType = receivingSchema.schema.describe().keys.input.label; return outputType == inputType; }