Skip to content

Commit

Permalink
Merge pull request #16 from buzcarter/feature/rollback_menu_lists_enh…
Browse files Browse the repository at this point in the history
…ancements_only

add Tbsp, gm, tsp, and Tbsp to recognized units;
  • Loading branch information
buzcarter committed Jun 17, 2024
2 parents bef73e1 + 33d1866 commit e3f1430
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 34 deletions.
26 changes: 12 additions & 14 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"label": "npm: build",
"detail": "node ./build.js"
}
]
"version": "2.0.0",
"tasks": [{
"type": "npm",
"script": "build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"label": "npm: build",
"detail": "node ./build.js"
}]
}
43 changes: 28 additions & 15 deletions build.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
/* eslint-disable no-console */
import {
basename, dirname, extname, join, resolve,
} from 'path';
import { basename, extname, join, resolve } from 'path';
import { rmSync, mkdirSync, rename } from 'fs';
import { cp, readdir, readFile } from 'fs/promises';
import sharp from 'sharp';
import { fileURLToPath } from 'url';

export const __dirname = dirname(fileURLToPath(import.meta.url));

import buildRecipes from './src/buildRecipes.js';
import buildRecipeIndex from './src/buildRecipeIndex.js';
import configs from './config.js';
import { __dirname, filterByExtension } from './src/libs/fsUtils.js';

import { ColorTypes, Colors } from './src/libs/ConsoleColors.js';

const THUMBNAIL_WIDTH = 260;

const filterByExtension = (fileList, basePath, allowedExtensions) => fileList
.filter((fileName) => allowedExtensions.includes(extname(fileName)))
.map((fileName) => ({
file: resolve(basePath, fileName),
fileName,
name: basename(fileName, extname(fileName)),
}));
const showOverrideMsg = (cmdArgs) => {
const { Reset } = ColorTypes;
const { Orange, Cyan, Yellow, Magenta } = Colors;
console.log(`\n${
Yellow}Using command line overrides:\n${Magenta}${JSON
.stringify(cmdArgs, null, 3)
.replace(/^(\s*)"([^"]+)": ("?)(.*?)("?)(,?)$/gm, `$1${Magenta}"${Orange}$2${Magenta}": ${Magenta}$3${Cyan}$4${Magenta}$5$6`)}${
Reset}\n`);
};

const showDoneMsg = (recipeCount, time) => {
const { Reset } = ColorTypes;
const { Orange, Cyan, Yellow } = Colors;
console.log(`\n${
Yellow}Processed ${
Cyan}${recipeCount}${
Yellow} recipes in ${
Cyan}${time}${
Orange}ms${
Reset
}\n`);
};

function setupOutputDir(outputPath) {
rmSync(outputPath, { recursive: true, force: true });
Expand Down Expand Up @@ -134,7 +147,7 @@ function getCommanLineOverrides(args) {
}, {});

if (cmdArgs && Object.keys(cmdArgs).length) {
console.log(`Using command line overrides: ${JSON.stringify(cmdArgs, null, 3)}`);
showOverrideMsg(cmdArgs);
}
return cmdArgs;
}
Expand Down Expand Up @@ -175,7 +188,7 @@ function main(opts) {
buildRecipeIndex(indexTemplate, options, markdownFiles, images, recipeInfo);

const endTime = new Date();
console.log(`Processed ${markdownFiles.length} recipes in ${endTime - startTime}ms`);
showDoneMsg(markdownFiles.length, endTime - startTime);
})
.catch((err) => {
console.error(err);
Expand Down
3 changes: 2 additions & 1 deletion src/buildRecipeIndex.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { resolve } from 'path';
import { writeFileSync } from 'fs';
import prettyHtml from 'pretty';
import { fileNameToTitleCase } from './libs/utils.js';

/* eslint-disable key-spacing */
const Substitutions = {
Expand Down Expand Up @@ -43,7 +44,7 @@ export default function buildRecipeIndex(indexTemplate, { defaultTheme, favicon,

fileList.forEach(({ name }) => {
const firstLetter = name.charAt(0).toUpperCase();
const displayName = name.replace(/-/g, ' ');
const displayName = fileNameToTitleCase(name);

// if the first letter of the recipe hasn't been
// seen yet, add to list of letters and put an achor in
Expand Down
27 changes: 24 additions & 3 deletions src/buildRecipes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { readFile, writeFile } from 'fs';
import showdown from 'showdown';
import prettyHtml from 'pretty';

import { ColorTypes, Colors } from './libs/ConsoleColors.js';
import {
linkify, shorten, replaceFractions, replaceQuotes, linkifyImages, getAuthor,
} from './libs/utils.js';
Expand Down Expand Up @@ -80,7 +81,7 @@ const RegExes = Object.freeze({
* "1/4 teaspoon vanilla extract"
* "1.5 oz gin"
*/
NUMERIC: /<li>(~?[\d½⅓⅔¼¾⅕⅖⅗⅘⅙⅚⅐⅛⅜⅝⅞/ .–-]+(?:(?:to|-) \d+)?(?:["gcltT]|oz|ml|lb|kg)?\.?)\s+(.*)\s*<\/li>/,
NUMERIC: /<li>(~?[\d½⅓⅔¼¾⅕⅖⅗⅘⅙⅚⅐⅛⅜⅝⅞/ .–-]+(?:(?:to|-) \d+)?(?:["gcltT]|cup|oz|ml|lb|kg|gm|tsp|Tbsp)?\.?)\s+(.*)\s*<\/li>/,
FRACTION_SYMBOL: /([½⅓⅔¼¾⅕⅖⅗⅘⅙⅚⅐⅛⅜⅝⅞])/g,

/** Custom meta tags */
Expand All @@ -90,6 +91,27 @@ const RegExes = Object.freeze({

const LINK_SUB_NAME = '<name>';

let warnNbr = 0;
const showWarnings = (name, warnings) => {
const { Reset } = ColorTypes;
const { Magenta, Cyan, Orange, CoolYellow, Yellow } = Colors;
if (warnNbr === 0) {
// eslint-disable-next-line no-console
console.warn(`\n${
Yellow}Somw recipes contain unrecognized sections. Content for these sections will be appear under the "${
Magenta}${SectionTypes.NOTES}${
Yellow}" section.${
Reset}\n`);
}
// eslint-disable-next-line no-console
console.warn(`${
CoolYellow}${++warnNbr}. ${
Cyan}${name}.md${
CoolYellow}: ${
Orange}${warnings}${
Reset}`);
};

function setHeadMeta(documentHtml, { author, favicon, ogImgURL, recipeName, titleSuffix }) {
return documentHtml
.replace(RegExes.PAGE_TITLE, `<title>${recipeName}${author ? ` by ${author}` : ''}${titleSuffix || ''}</title>`)
Expand Down Expand Up @@ -221,8 +243,7 @@ function convertRecipe(outputHTML, recipeHTML, opts) {
const heroImgURL = image ? `images/${image.fileName}` : '';

if (sectionMgr.hasWarnings) {
// eslint-disable-next-line no-console
console.warn(`${name}.md contains unknown sections [${sectionMgr.warnings}] that are included under "${SectionTypes.NOTES}"`);
showWarnings(name, sectionMgr.warnings);
}

outputHTML = sectionMgr.replace(outputHTML);
Expand Down
29 changes: 29 additions & 0 deletions src/libs/ConsoleColors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const HEX_ESC = '\x1b';

/* eslint-disable key-spacing */
export const ColorTypes = Object.freeze({
Reset: `${HEX_ESC}[0m`,
});

export const Colors = Object.freeze({
// Text colors (foreground colors)
Black: `${HEX_ESC}[30m`,
Blue: `${HEX_ESC}[34m`,
CoolYellow: `${HEX_ESC}[38;2;175;175;151m`,
Cyan: `${HEX_ESC}[36m`,
Gray: `${HEX_ESC}[90m`,
Green: `${HEX_ESC}[32m`,
Magenta: `${HEX_ESC}[35m`,
Orange: `${HEX_ESC}[38;5;208m`,
Pink: `${HEX_ESC}[38;5;175m`,
Purple: `${HEX_ESC}[38;5;99m`,
Red: `${HEX_ESC}[31m`,
White: `${HEX_ESC}[37m`,
Yellow: `${HEX_ESC}[33m`,
});
/* eslint-enable key-spacing */

export default {
ColorTypes,
Colors,
};
32 changes: 32 additions & 0 deletions src/libs/__tests__/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,35 @@ Dalgona coffee is a whipped coffee drink`,
});
});
});

describe('titleCase', () => {
const { titleCase } = utils;

it('should convert string to title case', () => {
const tests = [
{ value: 'hello world', expectedResult: 'Hello World' },
{ value: ' this is a test ', expectedResult: 'This Is A Test' },
];

tests.forEach(({ value, expectedResult }) => {
const result = titleCase(value);
expect(result).toBe(expectedResult);
});
});
});

describe('fileNameToTitleCase', () => {
const { fileNameToTitleCase } = utils;

it('should convert file name to title case', () => {
const tests = [
{ value: 'hello-world.js', expectedResult: 'Hello World.Js' },
{ value: ' anotherexample html---my--pie.lady', expectedResult: 'Anotherexample Html My Pie.Lady' },
];

tests.forEach(({ value, expectedResult }) => {
const result = fileNameToTitleCase(value);
expect(result).toBe(expectedResult);
});
});
});
18 changes: 18 additions & 0 deletions src/libs/fsUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {
basename,
dirname,
extname,
resolve,
} from 'path';
import { fileURLToPath } from 'url';

/** directory name of project root */
export const __dirname = resolve(dirname(fileURLToPath(import.meta.url)), '../..');

export const filterByExtension = (fileList, basePath, allowedExtensions) => fileList
.filter((fileName) => allowedExtensions.includes(extname(fileName)))
.map((fileName) => ({
file: resolve(basePath, fileName),
fileName,
name: basename(fileName, extname(fileName)),
}));
24 changes: 23 additions & 1 deletion src/libs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,30 @@ export const shorten = (value) => value
return domain;
});

/** brute-force approach: replaces `1/2` with `½` */
/**
* brute-force approach: replaces `1/2` with `½`
*/
export const replaceFractions = (value) => value
.replace(RegExes.FRACTIONS, (m) => FractionsHash[m]);

/**
* Replaces "straight" quotes with HTML encoded "curly" quotes. Avoids replacing quotes in HTML tags.
*/
export const replaceQuotes = (value) => value.replace(/(?<!=)"([^"\n>]+)"(?=[\s<])/g, '&ldquo;$1&rdquo;');

/**
* Converts a string to title case by replacing the first character of each word with uppercase.
* @param {string} value - The string to convert to title case.
* @returns {string} The string in title case.
*/
export const titleCase = (value) => value.trim().replace(/\b\w/g, (word) => word.toUpperCase());

/**
* Replaces "-" with spaces, removes double spaces, and returns the title case of the result.
* @param {string} value - The string to process.
* @returns {string} The processed string in title case.
*/
export const fileNameToTitleCase = (value) => {
const processedString = value.trim().replace(/-/g, ' ').replace(/\s+/g, ' ');
return titleCase(processedString);
};
7 changes: 7 additions & 0 deletions src/static/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
AddDefaultCharset UTF-8
<FilesMatch "\.(txt|md)$">
AddCharset UTF-8 .txt .md
</FilesMatch>
<FilesMatch "\.md$">
ForceType text/plain
</FilesMatch>

0 comments on commit e3f1430

Please sign in to comment.