mirror of
https://github.com/marcogll/passkit-generator.git
synced 2026-03-15 15:25:20 +00:00
Refactored all error messages, throws and tests. Added more throwing points and fixed others
This commit is contained in:
@@ -3,6 +3,7 @@ import * as path from "path";
|
||||
import { filesSymbol, freezeSymbol } from "../lib/Bundle";
|
||||
import FieldsArray from "../lib/FieldsArray";
|
||||
import { PassProps } from "../lib/schemas";
|
||||
import * as Messages from "../lib/messages";
|
||||
import {
|
||||
default as PKPass,
|
||||
localizationSymbol,
|
||||
@@ -292,22 +293,6 @@ describe("PKPass", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw error if a boolean parameter is received", () => {
|
||||
// @ts-expect-error
|
||||
expect(() => pass.setBarcodes(true)).toThrowError(
|
||||
TypeError,
|
||||
"Expected Schema.Barcode in setBarcodes but no one is valid.",
|
||||
);
|
||||
});
|
||||
|
||||
it("should ignore if a number parameter is received", () => {
|
||||
// @ts-expect-error
|
||||
expect(() => pass.setBarcodes(42)).toThrowError(
|
||||
TypeError,
|
||||
"Expected Schema.Barcode in setBarcodes but no one is valid.",
|
||||
);
|
||||
});
|
||||
|
||||
it("should autogenerate all the barcodes objects if a string is provided as message", () => {
|
||||
pass.setBarcodes("28363516282");
|
||||
expect(pass.props["barcodes"].length).toBe(4);
|
||||
@@ -424,8 +409,9 @@ describe("PKPass", () => {
|
||||
() => (passCP.transitType = "PKTransitTypeAir"),
|
||||
).toThrowError(
|
||||
TypeError,
|
||||
"Cannot set transitType on a pass with type different from 'boardingPass'.",
|
||||
Messages.TRANSIT_TYPE.UNEXPECTED_PASS_TYPE,
|
||||
);
|
||||
|
||||
expect(passCP.transitType).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -600,30 +586,30 @@ describe("PKPass", () => {
|
||||
it("should fail throw if lang is not a string", () => {
|
||||
expect(() => pass.localize(null)).toThrowError(
|
||||
TypeError,
|
||||
"Cannot set localization. Expected a string for 'lang' but received a object",
|
||||
Messages.LANGUAGES.INVALID_TYPE.replace("%s", "object"),
|
||||
);
|
||||
|
||||
expect(() => pass.localize(undefined)).toThrowError(
|
||||
TypeError,
|
||||
"Cannot set localization. Expected a string for 'lang' but received a undefined",
|
||||
Messages.LANGUAGES.INVALID_TYPE.replace("%s", "undefined"),
|
||||
);
|
||||
|
||||
// @ts-expect-error
|
||||
expect(() => pass.localize(5)).toThrowError(
|
||||
TypeError,
|
||||
"Cannot set localization. Expected a string for 'lang' but received a number",
|
||||
Messages.LANGUAGES.INVALID_TYPE.replace("%s", "number"),
|
||||
);
|
||||
|
||||
// @ts-expect-error
|
||||
expect(() => pass.localize(true)).toThrowError(
|
||||
TypeError,
|
||||
"Cannot set localization. Expected a string for 'lang' but received a boolean",
|
||||
Messages.LANGUAGES.INVALID_TYPE.replace("%s", "boolean"),
|
||||
);
|
||||
|
||||
// @ts-expect-error
|
||||
expect(() => pass.localize({})).toThrowError(
|
||||
TypeError,
|
||||
"Cannot set localization. Expected a string for 'lang' but received a object",
|
||||
Messages.LANGUAGES.INVALID_TYPE.replace("%s", "object"),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -820,12 +806,12 @@ describe("PKPass", () => {
|
||||
});
|
||||
|
||||
describe("[closePassSymbol]", () => {
|
||||
it("should add props to pass.json", () => {
|
||||
beforeEach(() => {
|
||||
pass.addBuffer(
|
||||
"pass.json",
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
boardingPass: {
|
||||
coupon: {
|
||||
headerFields: [],
|
||||
primaryFields: [],
|
||||
auxiliaryFields: [],
|
||||
@@ -836,7 +822,9 @@ describe("PKPass", () => {
|
||||
} as PassProps),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("should add props to pass.json", () => {
|
||||
pass.setBarcodes({
|
||||
format: "PKBarcodeFormatQR",
|
||||
message: "meh a test barcode",
|
||||
@@ -849,7 +837,7 @@ describe("PKPass", () => {
|
||||
expect(
|
||||
JSON.parse(pass[filesSymbol]["pass.json"].toString("utf-8")),
|
||||
).toEqual({
|
||||
boardingPass: {
|
||||
coupon: {
|
||||
headerFields: [],
|
||||
primaryFields: [],
|
||||
auxiliaryFields: [],
|
||||
@@ -869,23 +857,6 @@ describe("PKPass", () => {
|
||||
|
||||
it("Should warn user if no icons have been added to bundle", () => {
|
||||
console.warn = jasmine.createSpy("log");
|
||||
|
||||
pass.addBuffer(
|
||||
"pass.json",
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
boardingPass: {
|
||||
headerFields: [],
|
||||
primaryFields: [],
|
||||
auxiliaryFields: [],
|
||||
secondaryFields: [],
|
||||
backFields: [],
|
||||
},
|
||||
serialNumber: "h12kj5b12k3331",
|
||||
} as PassProps),
|
||||
),
|
||||
);
|
||||
|
||||
pass[closePassSymbol](true);
|
||||
|
||||
expect(console.warn).toHaveBeenCalledWith(
|
||||
@@ -894,22 +865,6 @@ describe("PKPass", () => {
|
||||
});
|
||||
|
||||
it("should create back again pass.strings files", () => {
|
||||
pass.addBuffer(
|
||||
"pass.json",
|
||||
Buffer.from(
|
||||
JSON.stringify({
|
||||
boardingPass: {
|
||||
headerFields: [],
|
||||
primaryFields: [],
|
||||
auxiliaryFields: [],
|
||||
secondaryFields: [],
|
||||
backFields: [],
|
||||
},
|
||||
serialNumber: "h12kj5b12k3331",
|
||||
} as PassProps),
|
||||
),
|
||||
);
|
||||
|
||||
pass.localize("it", {
|
||||
home: "casa",
|
||||
ciao: "hello",
|
||||
@@ -978,6 +933,24 @@ describe("PKPass", () => {
|
||||
pass[filesSymbol]["personalizationLogo@2x.png"],
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should throw if no pass type have specified", () => {
|
||||
pass.type = undefined; /** reset */
|
||||
|
||||
expect(() => pass[closePassSymbol](true)).toThrowError(
|
||||
TypeError,
|
||||
Messages.CLOSE.MISSING_TYPE,
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw if a boarding pass is exported without a transitType", () => {
|
||||
pass.type = "boardingPass";
|
||||
|
||||
expect(() => pass[closePassSymbol](true)).toThrowError(
|
||||
TypeError,
|
||||
Messages.CLOSE.MISSING_TRANSIT_TYPE,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("[static] from", () => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as Schemas from "./schemas";
|
||||
import formatMessage, * as Messages from "./messages";
|
||||
|
||||
/**
|
||||
* Class to represent lower-level keys pass fields
|
||||
@@ -24,15 +25,22 @@ export default class FieldsArray extends Array<Schemas.Field> {
|
||||
const validFields = fieldsData.reduce(
|
||||
(acc: Schemas.Field[], current: Schemas.Field) => {
|
||||
try {
|
||||
Schemas.assertValidity(Schemas.Field, current);
|
||||
Schemas.assertValidity(
|
||||
Schemas.Field,
|
||||
current,
|
||||
Messages.FIELDS.INVALID,
|
||||
);
|
||||
} catch (err) {
|
||||
console.warn(`Cannot add field: ${err}`);
|
||||
console.warn(err);
|
||||
return acc;
|
||||
}
|
||||
|
||||
if (this[poolSymbol].has(current.key)) {
|
||||
console.warn(
|
||||
`Cannot add field with key '${current.key}': another field already owns this key. Ignored.`,
|
||||
formatMessage(
|
||||
Messages.FIELDS.REPEATED_KEY,
|
||||
current.key,
|
||||
),
|
||||
);
|
||||
return acc;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import * as Signature from "./Signature";
|
||||
import * as Strings from "./StringsUtils";
|
||||
import * as Utils from "./utils";
|
||||
import { Stream } from "stream";
|
||||
import formatMessage, * as Messages from "./messages";
|
||||
|
||||
/** Exporting for tests specs */
|
||||
export const propsSymbol = Symbol("props");
|
||||
@@ -77,7 +78,11 @@ export default class PKPass extends Bundle {
|
||||
JSON.stringify(source[propsSymbol]),
|
||||
);
|
||||
} else {
|
||||
Schemas.assertValidity(Schemas.Template, source);
|
||||
Schemas.assertValidity(
|
||||
Schemas.Template,
|
||||
source,
|
||||
Messages.TEMPLATE.INVALID,
|
||||
);
|
||||
|
||||
buffers = await getModelFolderContents(source.model);
|
||||
certificates = source.certificates;
|
||||
@@ -180,7 +185,11 @@ export default class PKPass extends Bundle {
|
||||
*/
|
||||
|
||||
public set certificates(certs: Schemas.CertificatesSchema) {
|
||||
Schemas.assertValidity(Schemas.CertificatesSchema, certs);
|
||||
Schemas.assertValidity(
|
||||
Schemas.CertificatesSchema,
|
||||
certs,
|
||||
Messages.CERTIFICATES.INVALID,
|
||||
);
|
||||
this[certificatesSymbol] = certs;
|
||||
}
|
||||
|
||||
@@ -202,13 +211,15 @@ export default class PKPass extends Bundle {
|
||||
*/
|
||||
|
||||
public set transitType(value: Schemas.TransitType) {
|
||||
if (!this[propsSymbol].boardingPass) {
|
||||
throw new TypeError(
|
||||
"Cannot set transitType on a pass with type different from 'boardingPass'.",
|
||||
);
|
||||
if (this.type !== "boardingPass") {
|
||||
throw new TypeError(Messages.TRANSIT_TYPE.UNEXPECTED_PASS_TYPE);
|
||||
}
|
||||
|
||||
Schemas.assertValidity(Schemas.TransitType, value);
|
||||
Schemas.assertValidity(
|
||||
Schemas.TransitType,
|
||||
value,
|
||||
Messages.TRANSIT_TYPE.INVALID,
|
||||
);
|
||||
this[propsSymbol]["boardingPass"].transitType = value;
|
||||
}
|
||||
|
||||
@@ -291,7 +302,11 @@ export default class PKPass extends Bundle {
|
||||
*/
|
||||
|
||||
public set type(type: Schemas.PassTypesProps) {
|
||||
Schemas.assertValidity(Schemas.PassType, type);
|
||||
Schemas.assertValidity(
|
||||
Schemas.PassType,
|
||||
type,
|
||||
Messages.PASS_TYPE.INVALID,
|
||||
);
|
||||
|
||||
if (this.type) {
|
||||
/**
|
||||
@@ -360,9 +375,14 @@ export default class PKPass extends Bundle {
|
||||
return;
|
||||
}
|
||||
|
||||
this[importMetadataSymbol](
|
||||
validateJSONBuffer(buffer, Schemas.PassProps),
|
||||
);
|
||||
try {
|
||||
this[importMetadataSymbol](
|
||||
validateJSONBuffer(buffer, Schemas.PassProps),
|
||||
);
|
||||
} catch (err) {
|
||||
console.warn(formatMessage(Messages.PASS_SOURCE.INVALID, err));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding an empty buffer just for reference
|
||||
@@ -384,7 +404,7 @@ export default class PKPass extends Bundle {
|
||||
validateJSONBuffer(buffer, Schemas.Personalization);
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
"Personalization.json file has been omitted as invalid.",
|
||||
formatMessage(Messages.PERSONALIZATION.INVALID, err),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -456,18 +476,14 @@ export default class PKPass extends Bundle {
|
||||
} = data;
|
||||
|
||||
if (Object.keys(this[propsSymbol]).length) {
|
||||
console.warn(
|
||||
"The imported pass.json's properties will be joined with the current setted props. You might lose some data.",
|
||||
);
|
||||
console.warn(Messages.PASS_SOURCE.JOIN);
|
||||
}
|
||||
|
||||
Object.assign(this[propsSymbol], otherPassData);
|
||||
|
||||
if (!type) {
|
||||
if (!this[passTypeSymbol]) {
|
||||
console.warn(
|
||||
"Cannot find a valid type in pass.json. You won't be able to set fields until you won't set explicitly one.",
|
||||
);
|
||||
console.warn(Messages.PASS_SOURCE.UNKNOWN_TYPE);
|
||||
}
|
||||
} else {
|
||||
this.type = type;
|
||||
@@ -517,6 +533,10 @@ export default class PKPass extends Bundle {
|
||||
private [closePassSymbol](
|
||||
__test_disable_manifest_signature_generation__: boolean = false,
|
||||
) {
|
||||
if (!this.type) {
|
||||
throw new TypeError(Messages.CLOSE.MISSING_TYPE);
|
||||
}
|
||||
|
||||
const fileNames = Object.keys(this[filesSymbol]);
|
||||
|
||||
const passJson = Buffer.from(JSON.stringify(this[propsSymbol]));
|
||||
@@ -524,9 +544,7 @@ export default class PKPass extends Bundle {
|
||||
|
||||
const ICON_REGEX = /icon(?:@\d{1}x)?/;
|
||||
if (!fileNames.some((fileName) => ICON_REGEX.test(fileName))) {
|
||||
console.warn(
|
||||
"At least one icon file is missing in your bundle. Your pass won't be openable by any Apple Device.",
|
||||
);
|
||||
console.warn(Messages.CLOSE.MISSING_ICON);
|
||||
}
|
||||
|
||||
// *********************************** //
|
||||
@@ -571,7 +589,10 @@ export default class PKPass extends Bundle {
|
||||
for (let i = 0; i < fileNames.length; i++) {
|
||||
if (/personalization/.test(fileNames[i])) {
|
||||
console.warn(
|
||||
`Personalization file '${fileNames[i]}' have been removed from the bundle as the requirements for personalization are not met.`,
|
||||
formatMessage(
|
||||
Messages.CLOSE.PERSONALIZATION_REMOVED,
|
||||
fileNames[i],
|
||||
),
|
||||
);
|
||||
|
||||
delete this[filesSymbol][fileNames[i]];
|
||||
@@ -579,6 +600,14 @@ export default class PKPass extends Bundle {
|
||||
}
|
||||
}
|
||||
|
||||
// ******************************** //
|
||||
// *** BOARDING PASS VALIDATION *** //
|
||||
// ******************************** //
|
||||
|
||||
if (this.type === "boardingPass" && !this.transitType) {
|
||||
throw new TypeError(Messages.CLOSE.MISSING_TRANSIT_TYPE);
|
||||
}
|
||||
|
||||
// ****************************** //
|
||||
// *** SIGNATURE AND MANIFEST *** //
|
||||
// ****************************** //
|
||||
@@ -680,7 +709,7 @@ export default class PKPass extends Bundle {
|
||||
) {
|
||||
if (typeof lang !== "string") {
|
||||
throw new TypeError(
|
||||
`Cannot set localization. Expected a string for 'lang' but received a ${typeof lang}`,
|
||||
formatMessage(Messages.LANGUAGES.INVALID_TYPE, typeof lang),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -713,7 +742,7 @@ export default class PKPass extends Bundle {
|
||||
this[propsSymbol]["expirationDate"] = Utils.processDate(date);
|
||||
} catch (err) {
|
||||
throw new TypeError(
|
||||
`Cannot set expirationDate. Invalid date ${date}`,
|
||||
formatMessage(Messages.DATE.INVALID, "expirationDate", date),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -802,7 +831,7 @@ export default class PKPass extends Bundle {
|
||||
this[propsSymbol]["relevantDate"] = Utils.processDate(date);
|
||||
} catch (err) {
|
||||
throw new TypeError(
|
||||
`Cannot set relevantDate. Invalid date ${date}`,
|
||||
formatMessage(Messages.DATE.INVALID, "relevantDate", date),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -857,12 +886,6 @@ export default class PKPass extends Bundle {
|
||||
Schemas.Barcode,
|
||||
barcodes as Schemas.Barcode[],
|
||||
);
|
||||
|
||||
if (!finalBarcodes.length) {
|
||||
throw new TypeError(
|
||||
"Expected Schema.Barcode in setBarcodes but no one is valid.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this[propsSymbol]["barcodes"] = finalBarcodes;
|
||||
@@ -924,7 +947,7 @@ function validateJSONBuffer(
|
||||
try {
|
||||
contentAsJSON = JSON.parse(buffer.toString("utf8"));
|
||||
} catch (err) {
|
||||
throw new TypeError("Cannot validate Pass.json: invalid JSON");
|
||||
throw new TypeError(Messages.JSON.INVALID);
|
||||
}
|
||||
|
||||
return Schemas.validate(schema, contentAsJSON);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as path from "path";
|
||||
import * as Utils from "./utils";
|
||||
import formatMessage, { ERROR } from "./messages";
|
||||
import formatMessage, * as Messages from "./messages";
|
||||
import { promises as fs } from "fs";
|
||||
|
||||
/**
|
||||
@@ -54,12 +54,15 @@ export default async function getModelFolderContents(
|
||||
if (err.syscall === "open") {
|
||||
// file opening failed
|
||||
throw new Error(
|
||||
formatMessage(ERROR.MODELF_NOT_FOUND, err.path),
|
||||
formatMessage(
|
||||
Messages.MODELS.FILE_NO_OPEN,
|
||||
JSON.stringify(err),
|
||||
),
|
||||
);
|
||||
} else if (err.syscall === "scandir") {
|
||||
// directory reading failed
|
||||
throw new Error(
|
||||
formatMessage(ERROR.MODELF_FILE_NOT_FOUND, err.path),
|
||||
formatMessage(Messages.MODELS.DIR_NOT_FOUND, err.path),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
135
src/messages.ts
135
src/messages.ts
@@ -1,71 +1,86 @@
|
||||
export const ERROR = {
|
||||
CP_INIT:
|
||||
"Something went really bad in the %s initialization! Look at the log below this message. It should contain all the infos about the problem: \n%s",
|
||||
CP_NO_OPTS:
|
||||
"Cannot initialize the pass or abstract model creation: no options were passed.",
|
||||
CP_NO_CERTS:
|
||||
"Cannot initialize the pass creation: no valid certificates were passed.",
|
||||
PASSFILE_VALIDATION_FAILED:
|
||||
"Validation of pass type failed. Pass file is not a valid buffer or (more probably) does not respect the schema.\nRefer to https://apple.co/2Nvshvn to build a correct pass.",
|
||||
REQUIR_VALID_FAILED:
|
||||
"The options passed to Pass constructor does not meet the requirements.\nRefer to the documentation to compile them correctly.",
|
||||
MODEL_UNINITIALIZED:
|
||||
"Provided model ( %s ) matched but unitialized or may not contain icon or a valid pass.json.\nRefer to https://apple.co/2IhJr0Q, https://apple.co/2Nvshvn and documentation to fill the model correctly.",
|
||||
MODEL_NOT_VALID:
|
||||
"A model must be provided in form of path (string) or object { 'fileName': Buffer } in order to continue.",
|
||||
MODELF_NOT_FOUND: "Model %s not found. Provide a valid one to continue.",
|
||||
MODELF_FILE_NOT_FOUND: "File %s not found.",
|
||||
INVALID_CERTS:
|
||||
"Invalid certificate(s) loaded: %s. Please provide valid WWDR certificates and developer signer certificate and key (with passphrase).\nRefer to docs to obtain them.",
|
||||
INVALID_CERT_PATH: "Invalid certificate loaded. %s does not exist.",
|
||||
TRSTYPE_REQUIRED:
|
||||
"Cannot proceed with pass creation. transitType field is required for boardingPasses.",
|
||||
OVV_KEYS_BADFORMAT:
|
||||
"Cannot proceed with pass creation due to bad keys format in overrides.",
|
||||
NO_PASS_TYPE:
|
||||
"Cannot proceed with pass creation. Model definition (pass.json) has no valid type in it.\nRefer to https://apple.co/2wzyL5J to choose a valid pass type.",
|
||||
export const CERTIFICATES = {
|
||||
INVALID:
|
||||
"Invalid certificate(s) loaded. %s. Please provide valid WWDR certificates and developer signer certificate and key (with passphrase).\nRefer to docs to obtain them",
|
||||
} as const;
|
||||
|
||||
export const DEBUG = {
|
||||
TRSTYPE_NOT_VALID:
|
||||
'Transit type changing rejected as not compliant with Apple Specifications. Transit type would become "%s" but should be in [PKTransitTypeAir, PKTransitTypeBoat, PKTransitTypeBus, PKTransitTypeGeneric, PKTransitTypeTrain]',
|
||||
BRC_NOT_SUPPORTED:
|
||||
"Format not found among barcodes. Cannot set backward compatibility.",
|
||||
BRC_FORMATTYPE_UNMATCH:
|
||||
"Format must be a string or null. Cannot set backward compatibility.",
|
||||
BRC_AUTC_MISSING_DATA:
|
||||
"Unable to autogenerate barcodes. Data is not a string.",
|
||||
BRC_BW_FORMAT_UNSUPPORTED:
|
||||
"This format is not supported (by Apple) for backward support. Please choose another one.",
|
||||
BRC_NO_POOL:
|
||||
"Cannot set barcode: no barcodes found. Please set barcodes first. Barcode is for retrocompatibility only.",
|
||||
DATE_FORMAT_UNMATCH: "%s was not set due to incorrect date format.",
|
||||
NFC_INVALID:
|
||||
"Unable to set NFC properties: data not compliant with schema.",
|
||||
PRS_INVALID:
|
||||
"Unable to parse Personalization.json. File is not a valid JSON. Error: %s",
|
||||
PRS_REMOVED:
|
||||
"Personalization has been removed as it requires an NFC-enabled pass to work.",
|
||||
export const TRANSIT_TYPE = {
|
||||
UNEXPECTED_PASS_TYPE:
|
||||
"Cannot set transitType on a pass with type different from boardingPass.",
|
||||
INVALID:
|
||||
"Cannot set transitType because not compliant with Apple specifications. Refer to https://apple.co/3DHuAG4 for more - %s",
|
||||
} as const;
|
||||
|
||||
type ERROR_OR_DEBUG_MESSAGE =
|
||||
| typeof ERROR[keyof typeof ERROR]
|
||||
| typeof DEBUG[keyof typeof DEBUG];
|
||||
export const PASS_TYPE = {
|
||||
INVALID:
|
||||
"Cannot set type because not compliant with Apple specifications. Refer to https://apple.co/3aFpSfg for a list of valid props - %s",
|
||||
} as const;
|
||||
|
||||
export const TEMPLATE = {
|
||||
INVALID: "Cannot create pass from a template. %s",
|
||||
} as const;
|
||||
|
||||
export const FILTER_VALID = {
|
||||
INVALID: "Cannot validate property. %s",
|
||||
} as const;
|
||||
|
||||
export const FIELDS = {
|
||||
INVALID: "Cannot add field. %s",
|
||||
REPEATED_KEY:
|
||||
"Cannot add field with key '%s': another field already owns this key. Ignored.",
|
||||
} as const;
|
||||
|
||||
export const DATE = {
|
||||
INVALID: "Cannot set %s. Invalid date %s",
|
||||
} as const;
|
||||
|
||||
export const LANGUAGES = {
|
||||
INVALID_TYPE:
|
||||
"Cannot set localization. Expected a string for 'lang' but received %s",
|
||||
} as const;
|
||||
|
||||
export const BARCODES = {
|
||||
INVALID_POST: "",
|
||||
} as const;
|
||||
|
||||
export const PASS_SOURCE = {
|
||||
INVALID: "Cannot add pass.json to bundle because it is invalid. %s",
|
||||
UNKNOWN_TYPE:
|
||||
"Cannot find a valid type in pass.json. You won't be able to set fields until you won't set explicitly one.",
|
||||
JOIN: "The imported pass.json's properties will be joined with the current setted props. You might lose some data.",
|
||||
} as const;
|
||||
|
||||
export const PERSONALIZATION = {
|
||||
INVALID:
|
||||
"Cannot add personalization.json to bundle because it is invalid. %s",
|
||||
} as const;
|
||||
|
||||
export const JSON = {
|
||||
INVALID: "Cannot parse JSON. Invalid file",
|
||||
} as const;
|
||||
|
||||
export const CLOSE = {
|
||||
MISSING_TYPE: "Cannot proceed creating the pass because type is missing.",
|
||||
MISSING_ICON:
|
||||
"At least one icon file is missing in your bundle. Your pass won't be openable by any Apple Device.",
|
||||
PERSONALIZATION_REMOVED:
|
||||
"Personalization file '%s' have been removed from the bundle as the requirements for personalization are not met.",
|
||||
MISSING_TRANSIT_TYPE:
|
||||
"Cannot proceed creating the pass because transitType is missing on your boardingPass.",
|
||||
};
|
||||
|
||||
export const MODELS = {
|
||||
DIR_NOT_FOUND: "Cannot import model: directory %s not found.",
|
||||
FILE_NO_OPEN: "Cannot open model file. %s",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Creates a message with replaced values
|
||||
* @param {string} messageName
|
||||
* @param {any[]} values
|
||||
* @param messageName
|
||||
* @param values
|
||||
*/
|
||||
|
||||
export default function format(
|
||||
messageName: ERROR_OR_DEBUG_MESSAGE,
|
||||
...values: any[]
|
||||
) {
|
||||
export default function format(messageName: string, ...values: any[]) {
|
||||
// reversing because it is better popping than shifting.
|
||||
let replaceValues = values.reverse();
|
||||
return messageName.replace(/%s/g, () => {
|
||||
let next = replaceValues.pop();
|
||||
return next !== undefined ? next : "<passedValueIsUndefined>";
|
||||
});
|
||||
const replaceValues = values.reverse();
|
||||
return messageName.replace(/%s/g, () => replaceValues.pop());
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ import { PassFields, TransitType } from "./PassFields";
|
||||
import { Semantics } from "./SemanticTags";
|
||||
import { CertificatesSchema } from "./Certificates";
|
||||
|
||||
import formatMessage, * as Messages from "../messages";
|
||||
|
||||
const RGB_COLOR_REGEX =
|
||||
/rgb\(\s*(?:[01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\s*,\s*(?:[01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\s*,\s*(?:[01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\s*\)/;
|
||||
|
||||
@@ -194,10 +196,21 @@ export function isValid<T extends Object>(
|
||||
export function assertValidity<T>(
|
||||
schema: Joi.ObjectSchema<T> | Joi.StringSchema,
|
||||
data: T,
|
||||
customErrorMessage?: string,
|
||||
): void {
|
||||
const validation = schema.validate(data);
|
||||
|
||||
if (validation.error) {
|
||||
if (customErrorMessage) {
|
||||
console.warn(validation.error);
|
||||
throw new TypeError(
|
||||
`${validation.error.name} happened. ${formatMessage(
|
||||
customErrorMessage,
|
||||
validation.error.message,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
throw new TypeError(validation.error.message);
|
||||
}
|
||||
}
|
||||
@@ -239,7 +252,8 @@ export function filterValid<T extends Object>(
|
||||
return source.reduce((acc, current) => {
|
||||
try {
|
||||
return [...acc, validate(schema, current)];
|
||||
} catch {
|
||||
} catch (err) {
|
||||
console.warn(formatMessage(Messages.FILTER_VALID.INVALID, err));
|
||||
return [...acc];
|
||||
}
|
||||
}, []);
|
||||
|
||||
Reference in New Issue
Block a user