@phantomstudios/ft-lib
Version:
A collection of Javascript UI & tracking utils for FT sites
192 lines (181 loc) • 5.38 kB
text/typescript
import {
object,
string,
number,
boolean,
mixed,
InferType,
ValidationError,
} from "yup";
let disableAppFormatTransformValue = false;
//transform passed values to first character uppercase and replace spaces with underscores
const unifyValuesTransform = (value: string, disableTransform = false) => {
if (disableTransform) return value;
return (
value.trim().charAt(0).toUpperCase() +
value.trim().slice(1).toLowerCase().replace(/ /g, "_").replace(/-/g, "_")
);
};
//replace legacy 'AlphaGrid'..
const authorTransform = (value: string) => {
if (value.toLowerCase() === "alphagrid") {
return "Alpha_Grid";
}
return (
value.trim().charAt(0).toUpperCase() +
value.trim().slice(1).toLowerCase().replace(/ /g, "_").replace(/-/g, "_")
);
};
const configSchema = object({
product: string().oneOf(["paid-post", "commercial-ft-com"]),
url: string().required(),
feature: string().required().oneOf(["channel", "microsite", "commercial"]),
author: string().defined().default("").transform(authorTransform),
sponsor: string().defined().default(""),
articleName: string().defined().default(""),
videoName: string().defined().default(""),
videoType: string()
.optional()
.default("")
.transform(unifyValuesTransform)
.oneOf(["Feature", "Case_study", "Interview", "Animation", ""]),
hasVideo: boolean().optional().nullable(),
primaryTopic: string().defined().default("").transform(unifyValuesTransform),
secondaryTopic: string()
.defined()
.default("")
.transform(unifyValuesTransform),
advertiserIndustry: string().defined().default(""),
app: string()
.required()
.defined()
.transform((value) =>
unifyValuesTransform(value, disableAppFormatTransformValue),
)
.oneOf([
"Stream",
"Article",
"Animated_article",
"Immersive_article",
"Video",
"Article_with_video",
"Audio",
"Infographic",
"Interactive_infographic",
"Photo_essay",
"home-page",
"capabilities",
"my-products",
"audience",
"case-studies",
"markets",
"news-and-insights",
"other",
]),
publishDate: string().nullable().default(""),
isBranded: boolean().defined(),
contentType: string().defined().default("").transform(unifyValuesTransform),
campaign: string().defined().default(""),
server: string().equals(["https://spoor-api.ft.com/px.gif"]),
title: string().defined().default(""),
adbook_campaign_id: string().optional().default(""),
source_id: string().optional(),
wordCount: number().optional(),
commercial_product: string().optional().default("ft"),
});
const origamiEventSchema = object({
category: string()
.required()
.oneOf([
"page",
"video",
"audio",
"cta",
"scroll",
"brandedContent",
"internal click",
"external click",
"share",
"channel",
]),
action: string().required(),
app: string().nullable().notRequired(),
product: string().nullable().notRequired(),
source: string().nullable().notRequired(),
meta: mixed().nullable().notRequired(),
duration: number()
.nullable()
.notRequired()
.when("category", {
is: (value: string) => value === "video" || "audio",
then: () => number().required(),
}),
progress: number()
.nullable()
.notRequired()
.when("category", {
is: (value: string) => value === "video" || "audio",
then: () => number().required(),
}),
});
export type ConfigType = InferType<typeof configSchema>;
export type OrigamiEventType = InferType<typeof origamiEventSchema>;
export const parseConfig = (
config: ConfigType,
disableAppFormatTransform: boolean,
): ConfigType => {
disableAppFormatTransformValue = disableAppFormatTransform;
try {
//Replace app value based on deprecated hasVideo field and then remove hasVideo
if (config.hasVideo && config.app.toLowerCase() === "article") {
config.app = "Article_with_video";
}
delete config.hasVideo;
//Parse wordCount as number if not already
if (config.wordCount) {
config.wordCount = Number(config.wordCount);
}
return configSchema.cast(config);
} catch (err: any) {
err.errors?.map((err: Error) => {
console.info("FTTracker - config cast error: " + err);
});
return config;
}
};
export const validateConfig = (
config: ConfigType,
disableAppFormatTransform: boolean,
logValidationErrors: boolean,
): ValidationError[] | undefined => {
disableAppFormatTransformValue = disableAppFormatTransform;
try {
configSchema.validateSync(config, {
strict: false,
abortEarly: false,
});
} catch (err: any) {
if (logValidationErrors) {
err.errors?.map((err: ValidationError) => {
console.info("FTTracker - config validation error: " + err);
});
}
}
return undefined;
};
export const validateOrigamiEvent = (
config: OrigamiEventType,
): ValidationError[] | undefined => {
try {
const parsedConfig = origamiEventSchema.cast(config);
origamiEventSchema.validateSync(parsedConfig, {
strict: true,
abortEarly: false,
});
} catch (err: any) {
err.errors?.map((err: ValidationError) => {
console.info("FTTracker - Origami event validation error: " + err);
});
}
return undefined;
};