Skip to content

Commit

Permalink
Merge pull request #20 from brionmario/restructure-turbo
Browse files Browse the repository at this point in the history
feat: add ability to init medmark
  • Loading branch information
brionmario authored Dec 28, 2023
2 parents 649049c + 649586b commit 53b6b4a
Show file tree
Hide file tree
Showing 22 changed files with 416 additions and 122 deletions.
21 changes: 21 additions & 0 deletions .changeset/smooth-pandas-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
'medmark-playground': minor
'medmark': minor
---

Add ability to init Medmark by executing `medmark init`.

```bash
medmark init
```
This will do the following.

- Create a `.medmark` folder at the root of the execution with the following folder structure.

```bash
├── .medmark
│ ├── medium-export # Should extract the medium archive here.
│ │ ├── .gitkeep
│ ├── templates # Should contain the templates for Medmark.
│ │ ├── sample-medmark-template.js
```
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
enable-pre-post-scripts=true
1 change: 1 addition & 0 deletions lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"scripts": {
"build": "pnpm clean:dist && rollup -c rollup.config.cjs",
"clean:dist": "rimraf dist",
"dev": "pnpm clean:dist && rollup -c rollup.config.cjs --watch --watch.buildDelay 500",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,css,json,md,mdx}\"",
"test": "echo \"Error: no test specified\" && exit 0",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
Expand Down
4 changes: 2 additions & 2 deletions lib/rollup.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const pkg = require('./package.json');
module.exports = [
{
cache: false,
external: ['fs', 'path'],
input: 'src/index.ts',
output: [
{
Expand All @@ -59,9 +60,8 @@ module.exports = [
typescript({
tsconfig: './tsconfig.lib.json',
}),
// terser(),
terser(),
],
// external: ['fs', 'path'],
},
{
cache: false,
Expand Down
8 changes: 8 additions & 0 deletions lib/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@
* The delimiter used to split the HTML of embedded tweets
*/
export const EMBEDDED_TWEET_HTML_SPIT_DELIMITER: string = 'EMBEDDED_TWEET_HTML_SPIT_DELIMITER';

export const DEFAULT_MEDMARK_FOLDER_NAME: string = '.medmark';
export const DEFAULT_MEDMARK_LOGS_FOLDER_NAME: string = 'logs';
export const DEFAULT_MEDIUM_EXPORTS_FOLDER_NAME: string = 'medium-export';
export const DEFAULT_MEDIUM_OUTPUT_FOLDER_NAME: string = 'output';
export const DEFAULT_TEMPLATES_FOLDER_NAME: string = 'templates';
export const DEFAULT_MEDMARK_TEMPLATE_SAMPLE_FILENAME: string = 'sample-medmark-template.js';
export const MEDIUM_EXPORT_POSTS_FOLDER_NAME: string = 'posts';
7 changes: 4 additions & 3 deletions lib/src/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import fs, {WriteStream} from 'fs';
import cheerio, {CheerioAPI, Element, Cheerio} from 'cheerio';
import mkdirp from 'mkdirp';
import {join, resolve, basename, extname} from 'path';
import chalk from 'chalk';
import output from './output';
import {transformHtmlToMarkdown} from './markdown';
import Reporter from './reporter';
Expand Down Expand Up @@ -194,7 +195,7 @@ async function gatherPostData(
postsToSkip: string[],
): Promise<MedmarkTemplateRenderOptions> {
output.note({
bodyLines: [filePath],
bodyLines: [`${chalk.gray('[path]')} ${filePath}`],
title: 'Gathering post data started',
});

Expand All @@ -204,7 +205,7 @@ async function gatherPostData(
await inlineGists($cheerio, reporter);
} catch (e) {
output.error({
bodyLines: [`File Path: ${filePath}`, `Stack Trace: ${e}`],
bodyLines: [`${chalk.gray('[path]')} ${chalk.red(filePath)}`, `${chalk.gray('[stack]')} ${chalk.red(e)}`],
title: 'An error occurred while inlining Gists',
});
}
Expand Down Expand Up @@ -373,7 +374,7 @@ async function convertMediumFile(
const filename: string = basename(PATHS.file, '.html');

output.note({
bodyLines: [`PATH: ${PATHS.file}`, `FILE: ${filename}`],
bodyLines: [`${chalk.gray('[path]')} ${PATHS.file}`, `${chalk.gray('[output]')} ${filename}`],
title: 'Converting',
});

Expand Down
9 changes: 8 additions & 1 deletion lib/src/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import fs from 'fs-extra';
import {dirname, join, resolve} from 'path';
import ConfigurationService from './configuration-service';
import {DEFAULT_MEDMARK_FOLDER_NAME, DEFAULT_MEDMARK_LOGS_FOLDER_NAME} from './constants';

/**
* Defines the structure of the paths for the logs.
Expand Down Expand Up @@ -83,7 +84,13 @@ const PATHS: {
return resolve(join(PATHS.logs.root, articleId, 'meta.json'));
},
},
root: resolve(join('logs', ConfigurationService.getInstance().getRunnerTimestamp())),
root: resolve(
join(
DEFAULT_MEDMARK_FOLDER_NAME,
DEFAULT_MEDMARK_LOGS_FOLDER_NAME,
ConfigurationService.getInstance().getRunnerTimestamp(),
),
),
},
};

Expand Down
51 changes: 41 additions & 10 deletions lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,24 @@
* SOFTWARE.
*/

import {program} from 'commander';
import {Command} from 'commander';
import inquirer from 'inquirer';
import path from 'path';
import convert from './converter';
import ConfigurationService from './configuration-service';
import output from './output';
import debug from './debug';
import init from './init';
import {
DEFAULT_MEDIUM_EXPORTS_FOLDER_NAME,
DEFAULT_MEDIUM_OUTPUT_FOLDER_NAME,
DEFAULT_MEDMARK_FOLDER_NAME,
DEFAULT_MEDMARK_TEMPLATE_SAMPLE_FILENAME,
DEFAULT_TEMPLATES_FOLDER_NAME,
MEDIUM_EXPORT_POSTS_FOLDER_NAME,
} from './constants';

const program: Command = new Command();

program
.version('0.1.0')
Expand All @@ -49,18 +61,28 @@ program
debug: debugMode,
} = await inquirer.prompt([
{
message: 'Enter the path to the `posts` folder of the medium exported archive',
default: path.join(
DEFAULT_MEDMARK_FOLDER_NAME,
DEFAULT_MEDIUM_EXPORTS_FOLDER_NAME,
MEDIUM_EXPORT_POSTS_FOLDER_NAME,
),
message: 'Enter the path to the `posts` folder of the medium exported archive.',
name: 'input',
type: 'input',
},
{
default: 'output',
message: 'Enter destination folder for output files (default is "./")',
default: path.join(DEFAULT_MEDMARK_FOLDER_NAME, DEFAULT_MEDIUM_OUTPUT_FOLDER_NAME),
message: 'Enter destination folder for output files.',
name: 'output',
type: 'input',
},
{
message: 'Enter the path to the template file',
default: path.join(
DEFAULT_MEDMARK_FOLDER_NAME,
DEFAULT_TEMPLATES_FOLDER_NAME,
DEFAULT_MEDMARK_TEMPLATE_SAMPLE_FILENAME,
),
message: 'Enter the path to the template file.',
name: 'template',
type: 'input',
},
Expand All @@ -71,7 +93,7 @@ program
type: 'confirm',
},
{
message: 'Enter a comma-separated list of files to skip',
message: 'Enter a comma-separated list of files to skip.',
name: 'skip',
type: 'input',
},
Expand All @@ -87,11 +109,12 @@ program

output.log({
bodyLines: [
`→ ⬇️ INPUT: ${inputPath}`,
`→ ⬆️ OUTPUT (-o): ${outputPath}`,
`→ ⬇️ INPUT: ${inputPath}`,
`→ ⬆️ OUTPUT (-o): ${outputPath}`,
`→ 💅 TEMPLATE (-t): ${templatePath || 'none'}`,
`→ ❌ TO SKIP (-s): ${toSkip || 'none'}`,
`→ 🚧 SHOULD EXPORT DRAFTS? (-d): ${drafts}`,
`→ 🐞 DEBUG MODE? (-D): ${debugMode}`,
],
title: '💡 Following context has been initialized:',
});
Expand All @@ -104,7 +127,15 @@ program
}

convert(inputPath, outputPath, templatePath, drafts, toSkip);
})
.parse(process.argv);
});

program
.command('init')
.description('Initialize Medmark')
.action(async () => {
init();
});

program.parse(process.argv);

export * from './public-api';
138 changes: 138 additions & 0 deletions lib/src/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* MIT License
*
* Copyright (c) 2023, Brion Mario
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import fs from 'fs';
import path from 'path';
import {
DEFAULT_MEDIUM_EXPORTS_FOLDER_NAME,
DEFAULT_MEDMARK_FOLDER_NAME,
DEFAULT_MEDMARK_TEMPLATE_SAMPLE_FILENAME,
DEFAULT_TEMPLATES_FOLDER_NAME,
} from './constants';
import output from './output';

function init(): void {
try {
output.addNewline();
output.log({
title: '🚀 Initializing Medmark...',
});

const medmarkDir: string = path.join(process.cwd(), DEFAULT_MEDMARK_FOLDER_NAME);
const mediumExportDir: string = path.join(medmarkDir, DEFAULT_MEDIUM_EXPORTS_FOLDER_NAME);
const templatesDir: string = path.join(medmarkDir, DEFAULT_TEMPLATES_FOLDER_NAME);
const sampleTemplateFile: string = path.join(templatesDir, DEFAULT_MEDMARK_TEMPLATE_SAMPLE_FILENAME);

// Create the .medmark folder
if (!fs.existsSync(medmarkDir)) {
fs.mkdirSync(medmarkDir);
output.log({bodyLines: [output.check({text: `${DEFAULT_MEDMARK_FOLDER_NAME} folder created.`})]});
} else {
output.log({bodyLines: [output.skip({text: `${DEFAULT_MEDMARK_FOLDER_NAME} folder already exists.`})]});
}

// Create the medium-export folder and .gitkeep file
if (!fs.existsSync(mediumExportDir)) {
fs.mkdirSync(mediumExportDir);
fs.writeFileSync(path.join(mediumExportDir, '.gitkeep'), '');
output.log({bodyLines: [output.check({text: `${DEFAULT_MEDIUM_EXPORTS_FOLDER_NAME} folder created.`})]});
} else {
output.log({bodyLines: [output.skip({text: `${DEFAULT_MEDIUM_EXPORTS_FOLDER_NAME} folder already exists.`})]});
}

// Create the templates folder
if (!fs.existsSync(templatesDir)) {
fs.mkdirSync(templatesDir);
output.log({bodyLines: [output.check({text: `${DEFAULT_TEMPLATES_FOLDER_NAME} folder created.`})]});
} else {
output.log({bodyLines: [output.skip({text: `${DEFAULT_TEMPLATES_FOLDER_NAME} folder already exists.`})]});
}

// Create the sample-template.js file with content
const sampleTemplateContent: string = `\
const { frontMatterToYaml } = require('medmark');
module.exports = {
getOptions() {
return {
defaultCodeBlockLanguage: 'js',
folderForEachSlug: true,
imagePath: '/resources',
imageStorageStrategy: 'REMOTE',
};
},
render(data) {
const date = new Date(data.published);
const prettyDate = \`\${date.getFullYear()}-\${(date.getMonth() + 1).toString().padStart(2, 0)}-\${date.getDate().toString().padStart(2, 0)}\`;
const frontMatterAsJSON = {
slug: \`/posts/\${data.titleForSlug}/\`,
date: prettyDate,
title: data.title,
description: data.description,
authors: data.authors,
readingTime: data.readingTime,
draft: data.draft,
categories: data.categories,
tags: data.tags,
bannerImage: data.images.map(image => image.mediumUrl)[0],
ogImage: data.images.map(image => image.mediumUrl)[0],
images: data.images.map(image => image.mediumUrl),
};
const frontMatter = \`\\
---
\${frontMatterToYaml(frontMatterAsJSON)}
---
\${data.body}
\`;
return frontMatter;
},
};
`;

if (!fs.existsSync(sampleTemplateFile)) {
fs.writeFileSync(sampleTemplateFile, sampleTemplateContent);
output.log({bodyLines: [output.check({text: `${DEFAULT_MEDMARK_TEMPLATE_SAMPLE_FILENAME} file created.`})]});
} else {
output.log({
bodyLines: [output.skip({text: `${DEFAULT_MEDMARK_TEMPLATE_SAMPLE_FILENAME} file already exists.`})],
});
}

output.success({
title: '🎉 Initialization completed successfully.',
});
} catch (error) {
output.error({
bodyLines: [error.message.toString()],
title: '❌ Initialization failed.',
});
}
}

export default init;
Loading

0 comments on commit 53b6b4a

Please sign in to comment.