@croct/plug
Version:
A fully-featured devkit for building natively personalized applications.
380 lines (379 loc) • 10.3 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var structuredData_exports = {};
__export(structuredData_exports, {
extractArticle: () => extractArticle,
extractEntity: () => extractEntity,
extractProduct: () => extractProduct,
parseEntity: () => parseEntity
});
module.exports = __toCommonJS(structuredData_exports);
const typeMap = {
post: /* @__PURE__ */ new Set([
"BlogPosting",
"LiveBlogPosting",
"NewsArticle",
"AnalysisNewsArticle",
"AskPublicNewsArticle",
"BackgroundNewsArticle",
"OpinionNewsArticle",
"ReportageNewsArticle",
"ReviewNewsArticle",
"SocialMediaPosting",
"BlogPosting",
"DiscussionForumPosting",
"LiveBlogPosting"
]),
article: /* @__PURE__ */ new Set([
"Article",
"TechArticle",
"APIReference",
"Report",
"AdvertiserContentArticle",
"SatiricalArticle",
"ScholarlyArticle",
"MedicalScholarlyArticle"
]),
product: /* @__PURE__ */ new Set([
"Product",
"ProductCollection",
"ProductModel",
"ProductGroup",
"SomeProducts",
"Vehicle",
"BusOrCoach",
"Car",
"Motorcycle",
"MotorizedBicycle",
"Car",
"Motorcycle",
"IndividualProduct",
"DietarySupplement",
"Drug"
]),
service: /* @__PURE__ */ new Set([
"Service",
"BroadcastService",
"CableOrSatelliteService",
"FinancialProduct",
"FoodService",
"GovernmentService",
"TaxiService",
"WebAPI"
])
};
function parseEntity(content) {
const data = parseJsonLd(content);
if (data === null) {
return null;
}
return extractEntity(data);
}
function extractEntity(data) {
const type = getEntityType(data);
switch (type) {
case "article":
case "post": {
return {
type,
...extractArticle(data)
};
}
case "product":
case "service": {
return {
type,
...extractProduct(data)
};
}
}
return null;
}
function getEntityType(data) {
const type = getValue(data, "@type");
for (const [entityType, typeSet] of Object.entries(typeMap)) {
if (contains(typeSet, type)) {
return entityType;
}
}
return null;
}
function extractArticle(data) {
const postId = getValue(data, "identifier");
const post = {};
if (typeof postId === "string") {
post.id = postId;
}
const title = getValue(data, "headline", "name");
if (typeof title === "string") {
post.title = title;
}
const datePublished = getValue(data, "datePublished", "dateCreated");
const dateModified = getValue(data, "dateModified");
const updateTime = parseTimestamp(dateModified);
const publishTime = parseTimestamp(datePublished) ?? updateTime;
if (publishTime !== null) {
post.publishTime = publishTime;
if (updateTime !== null && updateTime > publishTime) {
post.updateTime = updateTime;
}
}
const url = getValue(data, "url", "mainEntityOfPage");
if (typeof url === "string" && URL.canParse(url)) {
post.url = url;
} else if (isObject(url)) {
const urlValue = getValue(url, "url", "@id");
if (typeof urlValue === "string" && URL.canParse(urlValue)) {
post.url = urlValue;
}
}
const tags = [];
const keywords = getValue(data, "keywords");
if (typeof keywords === "string") {
tags.push(
...keywords.split(",").map((keyword) => keyword.trim()).filter((keyword) => keyword.length > 0)
);
} else if (Array.isArray(keywords)) {
for (const keyword of keywords) {
if (typeof keyword === "string") {
tags.push(keyword);
}
}
}
if (tags.length > 0) {
post.tags = tags;
}
const categories = [];
for (const key of ["articleSection", "genre"]) {
const value = getValue(data, key);
if (typeof value === "string") {
categories.push(value);
} else if (Array.isArray(value)) {
for (const item of value) {
if (typeof item === "string") {
categories.push(item);
}
}
}
}
const about = getValue(data, "about");
if (isObject(about)) {
const aboutName = getValue(about, "name");
if (typeof aboutName === "string") {
categories.push(aboutName);
}
} else if (Array.isArray(about)) {
for (const item of about) {
if (isObject(item)) {
const itemName = getValue(item, "name");
if (typeof itemName === "string") {
categories.push(itemName);
}
}
}
}
if (categories.length > 0) {
post.categories = categories;
}
const authors = [];
const authorData = getValue(data, "author", "creator");
const authorList = Array.isArray(authorData) ? authorData : [authorData];
for (const author of authorList) {
if (typeof author === "string") {
authors.push(author);
} else if (isObject(author)) {
const name = getValue(author, "name");
if (typeof name === "string") {
authors.push(name);
}
}
}
if (authors.length > 0) {
post.authors = authors;
}
return post;
}
function extractProduct(data) {
const product = {};
const productId = getValue(data, "productID", "identifier");
if (typeof productId === "string") {
product.id = productId;
}
const productName = getValue(data, "name");
if (typeof productName === "string") {
product.name = productName;
}
const prices = [];
const urls = [];
const offersList = Array.isArray(data.offers) ? data.offers : [data.offers];
for (const offer of offersList) {
if (!isObject(offer)) {
continue;
}
const url = getValue(offer, "url");
if (typeof url === "string") {
urls.push(url);
}
for (const key of ["price", "lowPrice", "highPrice"]) {
const value = parseNumber(getValue(offer, key));
if (value !== null && value >= 0) {
prices.push(value);
}
}
const specifications = getValue(offer, "priceSpecification");
const specList = Array.isArray(specifications) ? specifications : [specifications];
for (const specification of specList) {
if (!isObject(specification)) {
continue;
}
for (const key of ["price", "minPrice", "maxPrice"]) {
const value = parseNumber(getValue(specification, key));
if (value !== null && value >= 0) {
prices.push(value);
}
}
}
}
if (prices.length > 0) {
const displayPrice = Math.min(...prices);
const originalPrice = Math.max(...prices);
product.displayPrice = displayPrice;
if (originalPrice > displayPrice) {
product.originalPrice = originalPrice;
}
}
const variant = [];
for (const key of ["color", "pattern", "size", "material", "model"]) {
const value = getValue(data, key);
if (typeof value === "string") {
variant.push(value);
} else if (isObject(value)) {
const name = getValue(value, "name");
if (typeof name === "string") {
variant.push(name);
}
}
}
if (variant.length > 0) {
product.variant = variant.join(", ");
}
const productSku = getValue(data, "sku");
if (typeof productSku === "string") {
product.sku = productSku;
}
const category = getValue(data, "category");
if (typeof category === "string") {
product.category = category;
} else if (isObject(category)) {
const name = getValue(category, "name");
if (typeof name === "string") {
product.category = name;
}
}
const brand = getValue(data, "brand");
if (typeof brand === "string") {
product.brand = brand;
} else if (isObject(brand)) {
const name = getValue(brand, "name");
if (typeof name === "string") {
product.brand = name;
}
}
const productUrl = getValue(data, "url");
if (typeof productUrl === "string") {
urls.unshift(productUrl);
}
for (const url of urls) {
if (URL.canParse(url)) {
product.url = url;
break;
}
}
const images = Array.isArray(data.image) ? data.image : [data.image];
for (const image of images) {
if (typeof image === "string" && URL.canParse(image)) {
product.imageUrl = image;
break;
}
if (isObject(image)) {
const imageUrl = getValue(image, "url");
if (typeof imageUrl === "string" && URL.canParse(imageUrl)) {
product.imageUrl = imageUrl;
break;
}
}
}
return product;
}
function parseJsonLd(content) {
try {
const data = JSON.parse(content);
if (isObject(data)) {
return data;
}
} catch {
}
return null;
}
function contains(set, value) {
if (typeof value === "string") {
return set.has(value);
}
return false;
}
function isObject(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function parseTimestamp(value) {
if (typeof value === "string") {
const date = Date.parse(value);
if (!Number.isNaN(date)) {
return date;
}
}
return null;
}
function parseNumber(value) {
if (typeof value === "number") {
return value;
}
if (typeof value === "string") {
const parsedValue = Number.parseFloat(value);
if (!Number.isNaN(parsedValue)) {
return parsedValue;
}
}
return null;
}
function getValue(object, ...keys) {
for (const key of keys) {
const value = object[key];
if (value === void 0 || value === null || typeof value === "string" && value.trim() === "") {
continue;
}
return value;
}
return null;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
extractArticle,
extractEntity,
extractProduct,
parseEntity
});