From 470ba2dc00926ed4437096266e6bf7721cea8ee3 Mon Sep 17 00:00:00 2001 From: Will Boyd Date: Sun, 16 Feb 2025 14:43:22 -0500 Subject: [PATCH] Catch initial parsing errors, shared.getValue() --- src/parser.js | 44 ++++++++++++++++++++++++++++---------------- src/shared.js | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/parser.js b/src/parser.js index cd5cda9..053432c 100644 --- a/src/parser.js +++ b/src/parser.js @@ -8,21 +8,33 @@ import * as translator from './translator.js'; export async function parseFilePromise() { console.log('\nParsing...'); const content = await fs.promises.readFile(shared.config.input, 'utf8'); - const allData = await xml2js.parseStringPromise(content, { + + const rootData = await xml2js.parseStringPromise(content, { trim: true, tagNameProcessors: [xml2js.processors.stripPrefix] + }).catch((ex) => { + ex.message = 'Could not parse XML. This likely means your import file is malformed.\n\n' + ex.message; + throw ex; }); - const channelData = allData.rss.channel[0].item; - const postTypes = getPostTypes(channelData); - const posts = collectPosts(channelData, postTypes); + const rssData = rootData.rss; + if (rssData === undefined) { + throw new Error('Could not find root node. This likely means your import file is malformed.') + } + rssData['wetm-expression'] = 'rss'; + + const channelData = shared.getValue(rssData, 'channel', 0); + const allPostData = shared.getValue(channelData, 'item'); + + const postTypes = getPostTypes(allPostData); + const posts = collectPosts(allPostData, postTypes); const images = []; if (shared.config.saveImages === 'attached' || shared.config.saveImages === 'all') { - images.push(...collectAttachedImages(channelData)); + images.push(...collectAttachedImages(allPostData)); } if (shared.config.saveImages === 'scraped' || shared.config.saveImages === 'all') { - images.push(...collectScrapedImages(channelData, postTypes)); + images.push(...collectScrapedImages(allPostData, postTypes)); } mergeImagesIntoPosts(images, posts); @@ -31,9 +43,9 @@ export async function parseFilePromise() { return posts; } -function getPostTypes(channelData) { +function getPostTypes(allPostData) { // search export file for all post types minus some specific types we don't want - const types = channelData + const types = allPostData .map(item => item.post_type[0]) .filter(type => ![ 'attachment', @@ -52,14 +64,14 @@ function getPostTypes(channelData) { return [...new Set(types)]; // remove duplicates } -function getItemsOfType(channelData, type) { - return channelData.filter(item => item.post_type[0] === type); +function getItemsOfType(allPostData, type) { + return allPostData.filter(item => item.post_type[0] === type); } -function collectPosts(channelData, postTypes) { +function collectPosts(allPostData, postTypes) { let allPosts = []; postTypes.forEach(postType => { - const postsForType = getItemsOfType(channelData, postType) + const postsForType = getItemsOfType(allPostData, postType) .filter(postData => postData.status[0] !== 'trash') .filter(postData => !(postType === 'page' && postData.post_name[0] === 'sample-page')) .map(postData => buildPost(postData)); @@ -106,8 +118,8 @@ function getPostMetaValue(metas, key) { return meta ? meta.meta_value[0] : undefined; } -function collectAttachedImages(channelData) { - const images = getItemsOfType(channelData, 'attachment') +function collectAttachedImages(allPostData) { + const images = getItemsOfType(allPostData, 'attachment') // filter to certain image file types .filter(attachment => attachment.attachment_url && (/\.(gif|jpe?g|png|webp)$/i).test(attachment.attachment_url[0])) .map(attachment => ({ @@ -120,10 +132,10 @@ function collectAttachedImages(channelData) { return images; } -function collectScrapedImages(channelData, postTypes) { +function collectScrapedImages(allPostData, postTypes) { const images = []; postTypes.forEach(postType => { - getItemsOfType(channelData, postType).forEach(postData => { + getItemsOfType(allPostData, postType).forEach(postData => { const postId = postData.post_id[0]; const postContent = postData.encoded[0]; const postLink = postData.link[0]; diff --git a/src/shared.js b/src/shared.js index 38316af..1a2216d 100644 --- a/src/shared.js +++ b/src/shared.js @@ -7,6 +7,44 @@ export function camelCase(str) { return str.replace(/-(.)/g, (match) => match[1].toUpperCase()); } +export function getValue(obj, propName, index) { + if (obj === undefined) { + throw new Error(`Could not find undefined.${propName}.`) + } + + let expression = `${obj['wetm-expression'] ?? 'object'}.${propName}`; + + const values = obj[propName]; + if (values === undefined) { + throw new Error(`Could not find ${expression}.`) + } + + if (index === undefined) { + values.forEach((value, index) => { + value['wetm-expression'] = `${expression}[${index}]`; + }); + return values; + } else { + expression += `[${index}]`; + + const value = values[index]; + if (value === undefined) { + throw new Error(`Could not find ${expression}.`) + } + + value['wetm-expression'] = expression; + return value; + } +} + +export function getOptionalValue(obj, propName, index) { + try { + return getValue(obj, propName, index); + } catch (ex) { + return undefined; + } +} + export function getSlugWithFallback(post) { return post.slug ? post.slug : 'id-' + post.id; }