Parting titles (as Hx).

This commit is contained in:
Laur Ivan 2022-06-28 15:39:44 +02:00
parent d8faf1ff67
commit aa30ceb903
7 changed files with 248 additions and 112 deletions

8
.vscode/launch.json vendored
View File

@ -11,6 +11,14 @@
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/dist/MakeMobiledoc.js",
"outFiles": ["${workspaceFolder}/**/*.js"]
},
{
"type": "pwa-node",
"request": "launch",
"name": "Markdown",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/dist/Markdown.js",
"outFiles": ["${workspaceFolder}/**/*.js"]
}
]
}

36
package-lock.json generated
View File

@ -18,10 +18,12 @@
"markdown-it-github-preamble": "^1.0.0",
"markdown-it-multimd-table": "^4.1.3",
"markdown-yaml-metadata-parser": "^3.0.0",
"mobiledoc-kit": "^0.14.0"
"mobiledoc-kit": "^0.14.0",
"yaml": "^2.1.1"
},
"devDependencies": {
"@types/node": "^14.14.31",
"@types/yaml": "^1.9.7",
"ts-node": "^9.1.1",
"typescript": "^4.3.2"
},
@ -64,6 +66,16 @@
"integrity": "sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q==",
"dev": true
},
"node_modules/@types/yaml": {
"version": "1.9.7",
"resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz",
"integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==",
"deprecated": "This is a stub types definition. yaml provides its own type definitions, so you do not need this installed.",
"dev": true,
"dependencies": {
"yaml": "*"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
@ -502,6 +514,14 @@
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"node_modules/yaml": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz",
"integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==",
"engines": {
"node": ">= 14"
}
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
@ -548,6 +568,15 @@
"integrity": "sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q==",
"dev": true
},
"@types/yaml": {
"version": "1.9.7",
"resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz",
"integrity": "sha512-8WMXRDD1D+wCohjfslHDgICd2JtMATZU8CkhH8LVJqcJs6dyYj5TGptzP8wApbmEullGBSsCEzzap73DQ1HJaA==",
"dev": true,
"requires": {
"yaml": "*"
}
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
@ -888,6 +917,11 @@
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"yaml": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.1.tgz",
"integrity": "sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw=="
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",

View File

@ -25,6 +25,7 @@
"license": "Apache-2.0",
"devDependencies": {
"@types/node": "^14.14.31",
"@types/yaml": "^1.9.7",
"ts-node": "^9.1.1",
"typescript": "^4.3.2"
},
@ -38,6 +39,7 @@
"markdown-it-github-preamble": "^1.0.0",
"markdown-it-multimd-table": "^4.1.3",
"markdown-yaml-metadata-parser": "^3.0.0",
"mobiledoc-kit": "^0.14.0"
"mobiledoc-kit": "^0.14.0",
"yaml": "^2.1.1"
}
}

View File

@ -2,109 +2,22 @@
* Load a file, parse it through markdonw-it and display its components
*/
import fs from "fs";
import MarkdownIt from "markdown-it";
import Token from "markdown-it/lib/token";
import metadataParser from "markdown-yaml-metadata-parser";
import { Convertor } from "./convertor/Processors";
const GhostAdminAPI = require("@tryghost/admin-api");
//const tabler = require("markdown-it-multimd-table");
let convertor = new Convertor("./src/data/markdown-it-example.md");
interface Stack {
tag: string;
meta: any;
}
let mdoc: string = convertor.process();
interface Process {
content: string;
token: Token;
}
function processBlock(buffer: string[], t: Token): Process {
let tbuf: string[] = [];
if (t.map != null)
for (let i = t.map[0]; i < t.map[1]; i++) tbuf.push(buffer[i]);
return {
content: tbuf.join("\n"),
token: t,
};
}
let v: string = fs.readFileSync("./src/data/markdown-it-example.md", {
encoding: "utf8",
flag: "r",
// Configure the client
const api = new GhostAdminAPI({
url: "http://localhost:2368",
// Admin API key goes here
key: "62ac6f5ab1479d0001082bd4:73341f843a5be78647c6f7e47d43d6cb09ec323df6d5706915df4685b3d46ce7",
version: "v4.0",
});
const parsed_md = metadataParser(v);
var src = MarkdownIt();
//src.use(tabler);
//import markdownItGithubPreamble from "markdown-it-github-preamble";
//src.use(markdownItGithubPreamble);
let lines: string[] = parsed_md.content.split("\n");
let tokens: Token[] = src.parse(parsed_md.content, { references: {} });
let stack: Stack[] = [];
//let tableBuffer: string[] = [];
let isTable = false;
//console.log(v);
tokens.forEach((value: Token) => {
let components: string[] = value.type.split("_");
let action: string | undefined = components.pop();
let name = components.join("_");
switch (action) {
case "open":
if (name === "table") isTable = true;
stack.push({ tag: value.tag, meta: value.meta } as never);
if (isTable) {
processBlock(lines, value);
}
break;
case "close":
if (name === "table") isTable = false;
stack.pop();
break;
case "fence":
processBlock(lines, value);
break;
case "inline":
let t: string = "";
let m: string = "";
stack.forEach((value) => {
t += "-" + value.tag;
m += ">" + JSON.stringify(value.meta);
});
if (isTable) {
console.log("++++", JSON.stringify(value));
} else {
console.log(t, m, value.content);
}
break;
// TODO: Make the 'FENCE' tag too!
default:
console.log("ERROR", components, action);
//throw new Error("Con't know tag" + action);
}
/*
console.log(
value.level,
"".padEnd(value.level, " "),
JSON.stringify({
type: value.type,
//level: value.level,
markup: value.markup,
//meta: value.meta,
content: value.content,
block: value.block,
//map: value.map,
//tag: value.tag,
//nesting: value.nesting,
info: value.info,
//children: value.children,
})
);
*/
});
api.posts
.add(JSON.parse(mdoc))
.then((response: any) => console.log(JSON.stringify(response)))
.catch((error: any) => console.error(error));

View File

179
src/convertor/Processors.ts Normal file
View File

@ -0,0 +1,179 @@
import { PostNodeBuilder, Renderer } from "mobiledoc-kit";
import fs from "fs";
import MarkdownIt from "markdown-it";
import Token from "markdown-it/lib/token";
import metadataParser from "markdown-yaml-metadata-parser";
interface Stack {
tag: string;
meta: any;
token: Token;
}
const renderer: any = Renderer;
const predefinedBlocks = ["blockquote", "table", "bullet_list", "ordered_list"];
export class Convertor {
markups: Record<string, any> = {};
markers: Record<string, any> = {};
sections: any[] = [];
builder: any = new PostNodeBuilder();
// The markdown bits (preamble and content)
//
preamble: string = "";
content: string = "";
// The line-by-line split of the markdown
//
lines: string[] = [];
tokens: Token[] = [];
/**
* Constructor
*
* @param filename the file name
*/
constructor(filename: string) {
this.initialize(filename);
}
/**
* Initialize/reset the convertor class.
*
* @param filename The file to be loaded
*/
public initialize(filename: string): Convertor {
this.builder = new PostNodeBuilder();
let content = fs.readFileSync(filename, {
encoding: "utf8",
flag: "r",
});
const parsed = metadataParser(content);
this.preamble = parsed.preamble;
this.content = parsed.content;
// Split the lines
//
this.lines = this.content.split("\n");
const markdownProcessor = MarkdownIt("commonmark");
this.tokens = markdownProcessor.parse(this.content, { references: {} });
return this;
}
public process(): string {
if (this.preamble === "" && this.content == "") {
throw new Error(
"Convertor not initialised. Please use initalize(...) first"
);
}
let stack: Stack[] = [];
let blockNesting = 0;
// Loop through tokens
this.tokens.forEach((value: Token) => {
let components: string[] = value.type.split("_");
let action: string | undefined = components.pop();
let name = components.join("_");
switch (action) {
case "open":
if (name in predefinedBlocks) blockNesting++;
stack.push({
tag: value.tag,
meta: value.meta,
token: value,
} as never);
break;
case "close":
if (name in predefinedBlocks) blockNesting--;
stack.pop();
break;
case "fence":
if (blockNesting == 0) {
console.log("Process fence...");
}
break;
case "inline":
/*
if (blockNesting == 0) {
let t: string = "";
let m: string = "";
stack.forEach((value) => {
t += "-" + value.tag;
m += ">" + JSON.stringify(value.meta);
});
console.log(t, m, value.content);
}
*/
break;
// TODO: Make the 'FENCE' tag too!
default:
console.log("ERROR", components, action);
//throw new Error("Con't know tag" + action);
}
if (value.level == 0) {
switch (name) {
case "table":
this.processBlock(value);
break;
case "heading":
//this.sections.push(this.processHeader(value));
break;
default:
this.processBlock(value);
}
} else if (blockNesting == 0 && action === "inline") {
console.log(value.level, stack[0].token.type);
switch (stack[0].token.type) {
case "heading_open":
this.sections.push(this.processHeader(stack, value));
break;
default:
this.processInline(stack, value);
}
}
});
// Aggregate the sections into a new mobiledoc
let post = this.builder.createPost(this.sections);
let result = JSON.stringify({
title: "A post",
mobiledoc: `${JSON.stringify(renderer.render(post, "0.3.1"))}`,
status: "draft",
author: "laur.ivan@gmail.com",
});
console.log("BLOG ENTRY------------------------------------");
console.log(result);
console.log("BLOG ENTRY------------------------------------");
return result;
}
private processInline(stack: Stack[], t: Token) {
console.log("*********************************************");
console.log(JSON.stringify(t), stack.length);
}
private processBlock(t: Token) {
let tbuf: string[] = [];
if (t.map != null)
for (let i = t.map[0]; i < t.map[1]; i++) tbuf.push(this.lines[i]);
//console.log("----------------------------------------------------");
//console.log(JSON.stringify(t));
return {
content: tbuf.join("\n"),
token: t,
};
}
private processHeader(stack: Stack[], t: Token): any {
console.log("+++++++++++++++++++++++++++++++++++++++++++++");
console.log(JSON.stringify(t));
let marker = this.builder.createMarker(t.content, []);
return this.builder.createMarkupSection(stack[0].tag, [marker]);
}
}

View File

@ -4,14 +4,14 @@
"uuid": "41ced005-2d7c-4965-907c-0c87f5bfe1af",
"title": "A post",
"slug": "a-post",
"mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[],\"cards\":[[\"markdown\",{\"markdown\":\"```js\\nlet value = 0\\n```\"}],[\"image\",{\"src\":\"http://localhost:2368/content/images/2022/06/ubuntu_black-orange_hex-1.png\",\"width\":758,\"height\":171,\"alt\":\"Ubuntu logo\"}]],\"markups\":[[\"strong\"]],\"sections\":[[1,\"p\",[[0,[0],0,\"Hi \"],[0,[],1,\" Bye\"]]],[10,0],[10,1],[1,\"p\",[]]],\"ghostVersion\":\"4.0\"}",
"mobiledoc": "{\"version\":\"0.3.1\",\"atoms\":[],\"cards\":[[\"markdown\",{\"markdown\":\"```js\\nlet value = 0\\n```\"}],[\"image\",{\"src\":\"http://localhost:2368/content/images/2022/06/ubuntu_black-orange_hex-1.png\",\"width\":758,\"height\":171,\"alt\":\"Ubuntu logo\"}]],\"markups\":[[\"strong\"]],\"sections\":[[1,\"p\",[[0,[0],0,\"Hi \"],[0,[],1,\" Bye\"]]],[10,0],[10,1],[1,\"h2\",[[0,[],0,\"A title\"]]],[1,\"h3\",[[0,[],0,\"A second title\"]]]],\"ghostVersion\":\"4.0\"}",
"comment_id": "62b81b265fb4ca000119c894",
"feature_image": "http://localhost:2368/content/images/2022/06/dragonfly.jpg",
"featured": false,
"status": "published",
"visibility": "public",
"created_at": "2022-06-26T08:39:02.000Z",
"updated_at": "2022-06-26T19:39:24.000Z",
"updated_at": "2022-06-28T13:31:24.000Z",
"published_at": "2022-06-26T08:39:23.000Z",
"custom_excerpt": null,
"codeinjection_head": null,
@ -39,7 +39,7 @@
"canonical_url": null,
"accent_color": null,
"created_at": "2022-05-31T12:27:26.000Z",
"updated_at": "2022-06-26T19:39:24.000Z",
"updated_at": "2022-06-28T13:31:24.000Z",
"url": "http://localhost:2368/tag/news/"
}
],
@ -61,9 +61,9 @@
"meta_title": null,
"meta_description": null,
"tour": null,
"last_seen": "2022-06-26T19:50:38.000Z",
"last_seen": "2022-06-28T13:30:38.000Z",
"created_at": "2022-05-31T12:27:26.000Z",
"updated_at": "2022-06-26T19:50:38.000Z",
"updated_at": "2022-06-28T13:30:38.000Z",
"roles": [
{
"id": "629609ae8b281d00012eb297",
@ -123,9 +123,9 @@
"meta_title": null,
"meta_description": null,
"tour": null,
"last_seen": "2022-06-26T19:50:38.000Z",
"last_seen": "2022-06-28T13:30:38.000Z",
"created_at": "2022-05-31T12:27:26.000Z",
"updated_at": "2022-06-26T19:50:38.000Z",
"updated_at": "2022-06-28T13:30:38.000Z",
"roles": [
{
"id": "629609ae8b281d00012eb297",
@ -157,12 +157,12 @@
"canonical_url": null,
"accent_color": null,
"created_at": "2022-05-31T12:27:26.000Z",
"updated_at": "2022-06-26T19:39:24.000Z",
"updated_at": "2022-06-28T13:31:24.000Z",
"url": "http://localhost:2368/tag/news/"
},
"email_segment": "all",
"url": "http://localhost:2368/a-post/",
"excerpt": "Hi Bye\n\nlet value = 0\n\n",
"excerpt": "Hi Bye\n\nlet value = 0\n\n\n\n\nA title\n\n\nA second title",
"og_image": null,
"og_title": null,
"og_description": null,