Skip to content

Commit

Permalink
abstract functions, better logging
Browse files Browse the repository at this point in the history
  • Loading branch information
revdavethompson committed Apr 25, 2023
1 parent 4b15217 commit 922c855
Show file tree
Hide file tree
Showing 11 changed files with 1,304 additions and 264 deletions.
21 changes: 0 additions & 21 deletions cli-wrapper.js

This file was deleted.

37 changes: 25 additions & 12 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,55 +9,68 @@ import path from 'path';
import nodemon from 'nodemon';
import { readFileSync, existsSync } from 'fs';
import { spawn } from 'child_process';
import chalk from 'chalk';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'));

const manuscriptDir = path.join(process.cwd(), 'manuscript');
const manRel = path.relative(process.cwd(), manuscriptDir);

const program = new Command();
program.version(packageJson.version);

async function buildHtml(manuscriptDir, outputDir, outputType) {
console.log(`Your convert params are: ${manuscriptDir}, ${outputDir}, ${outputType}`)
const outRel = path.relative(process.cwd(), outputDir);
console.log(` Manuscript Location: ${chalk.yellowBright(`/${manRel}/`)}\n Build Output Location: ${chalk.yellowBright(`/${outRel}/`)}\n\n`)
await convert(manuscriptDir, outputDir, outputType);
}

async function buildPdf(manuscriptDir, outputDir, outputType) {
await buildHtml(manuscriptDir, outputDir, outputType);

// Run the prince command-line tool
const prince = spawn('prince', ['build/pdf/index.html'], { stdio: 'inherit' });

prince.on('error', (error) => {
console.error(`Error: ${error.message}`);
});

return prince;
try {
const pdfOutDirRel = path.relative(process.cwd(), outputDir);
// Run the prince command-line tool
console.log(` 10. Building your Print PDF to ${chalk.yellowBright(`/${pdfOutDirRel}/index.pdf`)}\n `);
const prince = spawn('prince', ['build/pdf/index.html'], { stdio: 'inherit' });
prince.on('error', (error) => {
console.error(`Error: ${error.message}`);
});

return prince;
} catch (error) {
console.error(chalk.redBright(' Bummer. We couldn\'t build your pdf, because:'), chalk.redBright(error + '\n'));
}
}

program
.command('build')
.option('-t, --type <type>', 'Specify the output type (html or pdf)', 'html')
.description('Build the output from the manuscript markdown files')
.action(async (options) => {
console.log(`Building ${options.type.toUpperCase()}...`);
console.log(`\nBuilding ${options.type.toUpperCase()} Format...\n`);
if (options.type === 'html') {
await buildHtml(manuscriptDir, path.join(process.cwd(), 'build', 'html'), options.type);
} else if (options.type === 'pdf') {
await buildPdf(manuscriptDir, path.join(process.cwd(), 'build', 'pdf'), options.type);
} else {
console.error('Invalid output type specified. Use either "html" or "pdf".');
}
console.log(chalk.greenBright(`
---------------------------
Yay! All Finished!!
---------------------------
`));
});

program
.command('dev')
.option('-t, --type <type>', 'Specify the output type (html or pdf)', 'html')
.description('Run the development server with live-reloading')
.action(async (options) => {
console.log(`Running Nodemon and Webpack Server for ${options.type.toUpperCase()}...`);
console.log(`\nRunning Nodemon and Webpack Server for ${options.type.toUpperCase()}...\n`);
if (options.type === 'html') {
await buildHtml(manuscriptDir, path.join(process.cwd(), 'build', 'html'), options.type);
await runWebpackDevServerAsync('html');
Expand All @@ -78,7 +91,7 @@ function runNodemonAsync(outputType) {
});
}

// Run the webpack server using the user's webpack.config.js
// Run the webpack server using default settings
function runWebpackDevServerAsync(outputType) {
const server = spawn(
'npx',
Expand Down
3 changes: 1 addition & 2 deletions lib/compile-scss.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import sass from 'sass';
import path from 'path';
import chalk from 'chalk';

export async function compileSCSSToCSS(scssInput, cssOutput) {
console.log(`Rendering ${path.basename(scssInput)}...\n`);
export default async function compileSASS(scssInput, cssOutput) {
try {
const result = sass.renderSync({ file: scssInput, outputStyle: 'compressed' });
fs.writeFileSync(cssOutput, result.css);
Expand Down
79 changes: 55 additions & 24 deletions lib/convert.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import fs from 'fs';
import fse from 'fs-extra';
import path from 'path';
import { unified } from 'unified';
import remarkGfm from 'remark-gfm';
import remarkParse from 'remark-parse';
import remarkHtml from 'remark-html';
import yaml from 'js-yaml';
import lintEjs from './lint-ejs.js';
import renderEjs from './render-ejs.js';
import parseSmarty from './parse-smartypants.js';
import { compileSCSSToCSS } from './compile-scss.js';
import compileSASS from './compile-scss.js';
import chalk from 'chalk';
import parseMyst from './parse-myst.js';

// Convert Manuscript Pipeline
//--------------------
// CONVERT MANUSCRIPT INTO BUILD TYPE
//--------------------
export default async function convert(manuscriptDir, outputDir, outputType) {
Expand All @@ -20,9 +21,13 @@ export default async function convert(manuscriptDir, outputDir, outputType) {
// --------------------
let book;
try {
console.log(' 1. Loading your book.config.yml...\n')
book = yaml.load(fs.readFileSync(path.join(manuscriptDir, '../book.config.yml'), 'utf8'));
if (!book) {
console.warn(chalk.yellow(' Warning: The \'book\' variable is empty or undefined.\n This means your \'book.config.yml\' file isn\'t loading correctly.\n'));
}
} catch (error) {
console.error(chalk.red('Error Loading book.config.yml:'), chalk.red(error));
console.error(chalk.redBright('Error Loading book.config.yml:'), chalk.redBright(error));
}

// Conversion Constants
Expand All @@ -38,60 +43,85 @@ export default async function convert(manuscriptDir, outputDir, outputType) {
fs.mkdirSync(outputDir, { recursive: true });
}

console.log('Loading manuscript...\n');
console.log(' 2. Loading your manuscript...\n');
const manuscript = fs.readFileSync(entryPath, 'utf8');

// Lint the EJS Content (Check for Errors)
// --------------------
let lintedEjs;
const ejsLintOpt = book['ejs-lint-options']
try {
console.log(' 3. Checking your EJS syntax for errors...\n')
lintedEjs = await lintEjs(manuscript, ejsLintOpt);
console.log(chalk.green('Your EJS syntax look great!'));
if (!lintedEjs) {
console.warn(chalk.yellow(' Warning: lintedEjs content is empty or undefined.\n This means something isn\'t working in the linting (syntax checking) process.\n'));
}
} catch (error) {
console.error(chalk.red('Whoops. We found errors in your EJS syntax:'), chalk.red(error));
console.error(chalk.redBright('Whoops. We found errors in your EJS syntax:'), chalk.redBright(error));
}

// Render EJS Content
// --------------------
let processedEJS;
try {
console.log(' 4. Processing your EJS files...\n')
processedEJS = await renderEjs(lintedEjs, book, outputType, manuscriptDir, path);
console.log(chalk.green('Nice! Your EJS was rendered successfully!'))
if (!processedEJS) {
console.warn(chalk.yellow(' Warning: Your \'processedEJS\' variable is empty or undefined.\n This means something isn\'t working in the EJS conversion process.\n'));
}
} catch (error) {
console.error(chalk.red('Dang. We couldn\'t render your EJS:'), chalk.red(error));
console.error(chalk.redBright('Dang. We couldn\'t render your EJS:'), chalk.redBright(error));
}

let parsedMyST;
const mystOptions = book['myst-options'];
// Convert Markdown to HTML
// --------------------
let parsedMarkdown;
try {
console.log("\nProcessing MyST Markdown...\n");
parsedMyST = await parseMyST(processedEJS, mystOptions, outputType);
console.log(" 5. Converting your manuscript Markdown into HTML...\n");
parsedMarkdown = unified()
// convert markdown to a MD-AST syntax tree
.use(remarkParse)
// convert md-ast to gfm-ast (Github Flavored Markdown) and pass options
.use(remarkGfm, book['gfm-options'])
// convert gfm-ast to html-ast
// but don't git rid of none-markdown syntax
.use(remarkHtml, { sanitize: false })
.processSync(processedEJS)
// convert to a string
.toString();
if (!parsedMarkdown) {
console.warn(chalk.yellow(' Warning: Your parsedMarkdown variable is empty or undefined.\n This means something isn\'t working in the Markdown conversion funciton.\n'));
}
} catch (error) {
console.error(chalk.red('MyST Processing Error:'), chalk.red(error));
console.error(chalk.redBright('Markdown Processing Error:'), chalk.redBright(error));
}


// Use Smartypants to process quotes and symbols
// --------------------
let parsedSmarty;
try {
console.log("\nConverting quotes and symbols...\n");
parsedSmarty = await parseSmarty(processedEJS);
console.log(" 6. Converting quotes and symbols...\n");
parsedSmarty = await parseSmarty(parsedMarkdown);
if (!parsedSmarty) {
console.warn(chalk.yellow(' Warning: Your \'parsedSmarty\' variable is empty or undefined.\n This means something isn\'t working in the conversion of your quotes and symbols.\n'));
}
} catch (error) {
console.error(chalk.red('Smartypants Processing Error:'), chalk.red(error));
console.error(chalk.redBright('Smartypants Processing Error:'), chalk.redBright(error));
}


// Write Final Build Output
// --------------------
console.log("Writing final build to " + outputFile)
const relOutFile = path.relative(process.cwd(), outputFile);
console.log(` 7. Writing final build to ${chalk.yellowBright(`/${relOutFile}`)}\n`)
fs.writeFileSync(outputFile, parsedSmarty);

// Copy Manuscript Theme to Build Location
// --------------------
const themeSrcDir = path.join(manuscriptDir, 'theme');
const themeDestDir = path.join(outputDir, 'theme');
console.log("\nCopying Manuscript Theme to Build Location (ignoring scss/css)...\n")
const relTheme = path.relative(process.cwd(), themeDestDir);
console.log(` 8. Copying Manuscript Theme to ${chalk.yellowBright(`/${relTheme}/`)}\n`)

await fse.copy(themeSrcDir, themeDestDir, {
filter: (src) => {
Expand All @@ -111,10 +141,11 @@ export default async function convert(manuscriptDir, outputDir, outputType) {
const scssInput = path.join(manuscriptDir, 'theme', 'css', `styles.${outputType}.scss`);
const cssOutput = path.join(outputDir, 'theme', 'css', `styles.${outputType}.css`);

await compileSCSSToCSS(scssInput, cssOutput);
const relCssOut = path.relative(process.cwd(), cssOutput);
console.log(` 9. Compiling SASS and Copying to ${chalk.yellowBright(`/${relCssOut}`)}\n`)
await compileSASS(scssInput, cssOutput);

console.log("-------------------\nYay! All Finished!!\n-------------------\n");
} catch (error) {
console.error(chalk.red('\nError Converting Manuscript:'), chalk.red(error));
console.error(chalk.redBright('\nError Converting Manuscript:'), chalk.redBright(error));
}
}
1 change: 0 additions & 1 deletion lib/lint-ejs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import chalk from 'chalk';
export default async function lintEjs(ejsContent, ejsLintOpt) {
try {
const lintedEjs = await ejsLint(ejsContent, ejsLintOpt);
console.log('Linted EJS content:', lintedEjs);
return lintedEjs || ejsContent; // Return the original content if no linting errors are found
} catch (error) {
console.error(chalk.red('Error Linting EJS Content:'), chalk.red(error));
Expand Down
20 changes: 20 additions & 0 deletions lib/load-book-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { readFileSync, existsSync } from 'fs';
import yaml from 'js-yaml';
import chalk from 'chalk';

export default async function loadBookConfig(bookPath) {
const bookConfigPath = bookPath;

if (!existsSync(bookConfigPath)) {
console.error(chalk.red('book.config.yml not found in the current working directory.'));
process.exit(1);
}

try {
const bookConfig = yaml.load(readFileSync(bookConfigPath, 'utf8'));
return bookConfig;
} catch (error) {
console.error(chalk.redBright('Error loading book.config.yml:'), chalk.redBright(error));
process.exit(1);
}
}
Loading

0 comments on commit 922c855

Please sign in to comment.