Convert to ES modules and related changes

This commit is contained in:
Will Boyd
2025-01-18 14:22:53 -05:00
parent cd5155cde0
commit 22d332a20f
11 changed files with 449 additions and 410 deletions
+81
View File
@@ -0,0 +1,81 @@
import * as luxon from 'luxon';
import * as settings from './settings.js';
// get author, without decoding
// WordPress doesn't allow funky characters in usernames anyway
export function getAuthor(post) {
return post.data.creator[0];
}
// get array of decoded category names, filtered as specified in settings
export function getCategories(post) {
if (!post.data.category) {
return [];
}
const categories = post.data.category
.filter(category => category.$.domain === 'category')
.map(({ $: attributes }) => decodeURIComponent(attributes.nicename));
return categories.filter(category => !settings.filter_categories.includes(category));
}
// get cover image filename, previously decoded and set on post.meta
// this one is unique as it relies on special logic executed by the parser
export function getCoverImage(post) {
return post.meta.coverImage;
}
// get post date, optionally formatted as specified in settings
// this value is also used for year/month folders, date prefixes, etc. as needed
export function getDate(post) {
const dateTime = luxon.DateTime.fromRFC2822(post.data.pubDate[0], { zone: settings.custom_date_timezone });
if (settings.custom_date_formatting) {
return dateTime.toFormat(settings.custom_date_formatting);
} else if (settings.include_time_with_date) {
return dateTime.toISO();
} else {
return dateTime.toISODate();
}
}
// get excerpt, not decoded, newlines collapsed
export function getExcerpt(post) {
return post.data.encoded[1].replace(/[\r\n]+/gm, ' ');
}
// get ID
export function getId(post) {
return post.data.post_id[0];
}
// get slug, previously decoded and set on post.meta
export function getSlug(post) {
return post.meta.slug;
}
// get array of decoded tag names
export function getTags(post) {
if (!post.data.category) {
return [];
}
const categories = post.data.category
.filter(category => category.$.domain === 'post_tag')
.map(({ $: attributes }) => decodeURIComponent(attributes.nicename));
return categories;
}
// get simple post title, but not decoded like other frontmatter string fields
export function getTitle(post) {
return post.data.title[0];
}
// get type, often this will always be "post"
// but can also be "page" or other custom types
export function getType(post) {
return post.data.post_type[0];
}
+10 -15
View File
@@ -1,15 +1,12 @@
const fs = require('fs');
const requireDirectory = require('require-directory');
const xml2js = require('xml2js');
import fs from 'fs';
import xml2js from 'xml2js';
const shared = require('./shared');
const settings = require('./settings');
const translator = require('./translator');
import * as shared from './shared.js';
import * as settings from './settings.js';
import * as translator from './translator.js';
import * as frontmatter from './frontmatter.js';
// dynamically requires all frontmatter getters
const frontmatterGetters = requireDirectory(module, './frontmatter', { recurse: false });
async function parseFilePromise(config) {
export async function parseFilePromise(config) {
console.log('\nParsing...');
const content = await fs.promises.readFile(config.input, 'utf8');
const allData = await xml2js.parseStringPromise(content, {
@@ -174,19 +171,17 @@ function mergeImagesIntoPosts(images, posts) {
function populateFrontmatter(posts) {
posts.forEach(post => {
const frontmatter = {};
post.frontmatter = {};
settings.frontmatter_fields.forEach(field => {
const [key, alias] = field.split(':');
let frontmatterGetter = frontmatterGetters[key];
let frontmatterGetter = frontmatter['get' + key.replace(/^./, (match) => match.toUpperCase())];
if (!frontmatterGetter) {
throw `Could not find a frontmatter getter named "${key}".`;
}
frontmatter[alias || key] = frontmatterGetter(post);
post.frontmatter[alias || key] = frontmatterGetter(post);
});
post.frontmatter = frontmatter;
});
}
exports.parseFilePromise = parseFilePromise;
+8 -8
View File
@@ -2,7 +2,7 @@
// Order is preserved. If a field has an empty value, it will not be included. You can rename a
// field by providing an alias after a ':'. For example, 'date:created' will include 'date' in
// frontmatter, but renamed to 'created'.
exports.frontmatter_fields = [
export const frontmatter_fields = [
'title',
'date',
'categories',
@@ -12,29 +12,29 @@ exports.frontmatter_fields = [
// Time in ms to wait between requesting image files. Increase this if you see timeouts or
// server errors.
exports.image_file_request_delay = 500;
export const image_file_request_delay = 500;
// Time in ms to wait between saving Markdown files. Increase this if your file system becomes
// overloaded.
exports.markdown_file_write_delay = 25;
export const markdown_file_write_delay = 25;
// Enable this to include time with post dates. For example, "2020-12-25" would become
// "2020-12-25T11:20:35.000Z".
exports.include_time_with_date = false;
export const include_time_with_date = false;
// Override post date formatting with a custom formatting string (for example: 'yyyy LLL dd').
// Tokens are documented here: https://moment.github.io/luxon/#/parsing?id=table-of-tokens. If
// set, this takes precedence over include_time_with_date.
exports.custom_date_formatting = '';
export const custom_date_formatting = '';
// Specify the timezone used for post dates. See available zone values and examples here:
// https://moment.github.io/luxon/#/zones?id=specifying-a-zone.
exports.custom_date_timezone = 'utc';
export const custom_date_timezone = 'utc';
// Categories to be excluded from post frontmatter. This does not filter out posts themselves,
// just the categories listed in their frontmatter.
exports.filter_categories = ['uncategorized'];
export const filter_categories = ['uncategorized'];
// Strict SSL is enabled as the safe default when downloading images, but will not work with
// self-signed servers. You can disable it if you're getting a "self-signed certificate" error.
exports.strict_ssl = true;
export const strict_ssl = true;
+1 -3
View File
@@ -1,4 +1,4 @@
function getFilenameFromUrl(url) {
export function getFilenameFromUrl(url) {
let filename = url.split('/').slice(-1)[0];
try {
filename = decodeURIComponent(filename)
@@ -8,5 +8,3 @@ function getFilenameFromUrl(url) {
}
return filename;
}
exports.getFilenameFromUrl = getFilenameFromUrl;
+5 -8
View File
@@ -1,7 +1,7 @@
const turndown = require('turndown');
const turndownPluginGfm = require('turndown-plugin-gfm');
import turndown from 'turndown';
import turndownPluginGfm from 'turndown-plugin-gfm';
function initTurndownService() {
export function initTurndownService() {
const turndownService = new turndown({
headingStyle: 'atx',
bulletListMarker: '-',
@@ -73,7 +73,7 @@ function initTurndownService() {
// preserve <figcaption>
turndownService.addRule('figcaption', {
filter: 'figcaption',
replacement: (content, node) => {
replacement: (content) => {
// extra newlines are necessary for markdown and HTML to render correctly together
return '\n\n<figcaption>\n\n' + content + '\n\n</figcaption>\n\n';
}
@@ -94,7 +94,7 @@ function initTurndownService() {
return turndownService;
}
function getPostContent(postData, turndownService, config) {
export function getPostContent(postData, turndownService, config) {
let content = postData.encoded[0];
// insert an empty div element between double line breaks
@@ -124,6 +124,3 @@ function getPostContent(postData, turndownService, config) {
return content;
}
exports.initTurndownService = initTurndownService;
exports.getPostContent = getPostContent;
+7 -12
View File
@@ -1,10 +1,8 @@
const camelcase = require('camelcase');
const commander = require('commander');
const fs = require('fs');
const inquirer = require('inquirer');
const path = require('path');
const package = require('../package.json');
import camelcase from 'camelcase';
import * as commander from 'commander';
import fs from 'fs';
import inquirer from 'inquirer';
import path from 'path';
// all user options for command line and wizard are declared here
const options = [
@@ -77,7 +75,7 @@ const options = [
}
];
async function getConfig(argv) {
export async function getConfig(argv) {
extendOptionsData();
const unaliasedArgv = replaceAliases(argv);
const opts = parseCommandLine(unaliasedArgv);
@@ -160,7 +158,6 @@ function parseCommandLine(argv) {
// setup for help output
commander.program
.name('node index.js')
.version('v' + package.version, '-v, --version', 'Display version number')
.helpOption('-h, --help', 'See the thing you\'re looking at right now')
.addHelpText('after', '\nMore documentation is at https://github.com/lonekorean/wordpress-export-to-markdown');
@@ -180,7 +177,7 @@ function parseCommandLine(argv) {
}
function coerceBoolean(value) {
return !['false', 'no', '0'].includes(value.toLowerCase());
return !['false', 'no', '0'].includes(value.toString().toLowerCase());
}
function coercePath(value) {
@@ -197,5 +194,3 @@ function validateFile(value) {
return isValid ? true : 'Unable to find file: ' + path.resolve(value);
}
exports.getConfig = getConfig;
+10 -12
View File
@@ -1,15 +1,15 @@
const axios = require('axios');
const chalk = require('chalk');
const fs = require('fs');
const http = require('http');
const https = require('https');
const luxon = require('luxon');
const path = require('path');
import axios from 'axios';
import chalk from 'chalk';
import fs from 'fs';
import http from 'http';
import https from 'https';
import * as luxon from 'luxon';
import path from 'path';
const shared = require('./shared');
const settings = require('./settings');
import * as shared from './shared.js';
import * as settings from './settings.js';
async function writeFilesPromise(posts, config) {
export async function writeFilesPromise(posts, config) {
await writeMarkdownFilesPromise(posts, config);
await writeImageFilesPromise(posts, config);
}
@@ -215,5 +215,3 @@ function getPostPath(post, config) {
function checkFile(path) {
return fs.existsSync(path);
}
exports.writeFilesPromise = writeFilesPromise;