add parsing of []() enclosures
This commit is contained in:
parent
f6c348bab0
commit
cd485f4259
|
@ -106,10 +106,75 @@ export default class MString {
|
||||||
return (chr === ' ' || chr === '\t' || chr === '\n');
|
return (chr === ' ' || chr === '\t' || chr === '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check if the current '[' is part of a [y](z) enclosure
|
||||||
|
* returns [y, z] if it is enclosure, null otherwise
|
||||||
|
* moves iter to last closing braked if it is enclosure
|
||||||
|
*/
|
||||||
|
checkIfEnclosure(zIsLink) {
|
||||||
|
const yStart = this.iter + 1;
|
||||||
|
|
||||||
|
let yEnd = yStart;
|
||||||
|
while (this.txt[yEnd] !== ']') {
|
||||||
|
const chr = this.txt[yEnd];
|
||||||
|
if (yEnd >= this.txt.length
|
||||||
|
|| chr === '\n'
|
||||||
|
|| chr === '['
|
||||||
|
|| chr === '('
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
yEnd += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let zStart = yEnd + 1;
|
||||||
|
if (this.txt[zStart] !== '(') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
zStart += 1;
|
||||||
|
|
||||||
|
let zEnd = zStart;
|
||||||
|
let z = null;
|
||||||
|
while (this.txt[zEnd] !== ')') {
|
||||||
|
const chr = this.txt[zEnd];
|
||||||
|
if (zEnd >= this.txt.length
|
||||||
|
|| chr === '\n'
|
||||||
|
|| chr == '['
|
||||||
|
|| chr == '('
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (zIsLink && chr === ':') {
|
||||||
|
// set this.iter temporarily to be able to use thischeckIfLink
|
||||||
|
const oldIter = this.iter;
|
||||||
|
this.iter = zEnd;
|
||||||
|
z = this.checkIfLink();
|
||||||
|
zEnd = this.iter;
|
||||||
|
this.iter = oldIter;
|
||||||
|
if (z === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
zEnd += 1;
|
||||||
|
}
|
||||||
|
if (zEnd < zStart + 1 || ( !z && zIsLink )) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!zIsLink) {
|
||||||
|
z = this.txt.slice(zStart, zEnd);
|
||||||
|
}
|
||||||
|
const y = this.txt.slice(yStart, yEnd);
|
||||||
|
|
||||||
|
this.iter = zEnd;
|
||||||
|
return [y, z];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convoluted way to check if the current ':' is part of a link
|
* Convoluted way to check if the current ':' is part of a link
|
||||||
* we do not check for a 'http' because we might support application links
|
* we do not check for a 'http' because we might support application links
|
||||||
* like telegram://... or discord://..
|
* like tg://... or discord://..
|
||||||
* returns the link or false if there is none
|
* returns the link or false if there is none
|
||||||
* moves iter forward to after the link, if there's one
|
* moves iter forward to after the link, if there's one
|
||||||
*/
|
*/
|
||||||
|
@ -126,26 +191,14 @@ export default class MString {
|
||||||
linkStart += 1;
|
linkStart += 1;
|
||||||
|
|
||||||
cIter += 3;
|
cIter += 3;
|
||||||
/* just some most basic test */
|
|
||||||
let dots = 0;
|
|
||||||
let slashes = 0;
|
|
||||||
for (; cIter < this.txt.length
|
for (; cIter < this.txt.length
|
||||||
&& !MString.isWhiteSpace(this.txt[cIter])
|
&& !MString.isWhiteSpace(this.txt[cIter])
|
||||||
&& this.txt[cIter] !== ')'; cIter += 1
|
&& this.txt[cIter] !== ')'; cIter += 1
|
||||||
) {
|
);
|
||||||
if (this.txt[cIter] === '.') {
|
if (cIter < this.iter + 4) {
|
||||||
if (slashes !== 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
dots += 1;
|
|
||||||
} else if (this.txt[cIter] === '/') {
|
|
||||||
slashes += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!dots || (!slashes && this.txt[cIter - 1] === '.')) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* special case where someone pasted a http link after a text
|
/* special case where someone pasted a http link after a text
|
||||||
* without space in between
|
* without space in between
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -75,15 +75,45 @@ function parseMParagraph(text, opts, breakChar) {
|
||||||
* pure link
|
* pure link
|
||||||
*/
|
*/
|
||||||
const link = text.checkIfLink();
|
const link = text.checkIfLink();
|
||||||
if (link) {
|
if (link !== null) {
|
||||||
const startLink = text.iter - link.length;
|
const startLink = text.iter - link.length;
|
||||||
if (pStart < startLink) {
|
if (pStart < startLink) {
|
||||||
pArray.push(text.slice(pStart, startLink));
|
pArray.push(text.slice(pStart, startLink));
|
||||||
}
|
}
|
||||||
pArray.push(['l', link, link]);
|
pArray.push(['l', null, link]);
|
||||||
pStart = text.iter;
|
pStart = text.iter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
} else if (chr === '[') {
|
||||||
|
/*
|
||||||
|
* x[y](z) enclosure
|
||||||
|
*/
|
||||||
|
let oldPos = text.iter;
|
||||||
|
let x = null;
|
||||||
|
if (text.iter > 0) {
|
||||||
|
text.move(-1);
|
||||||
|
x = text.getChar();
|
||||||
|
text.setIter(oldPos);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* x decides what element it is
|
||||||
|
* defaults to ordinary link
|
||||||
|
*/
|
||||||
|
let tag = 'l'
|
||||||
|
let zIsLink = true;
|
||||||
|
if (x === '!') {
|
||||||
|
tag = 'img';
|
||||||
|
oldPos -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const encArr = text.checkIfEnclosure(zIsLink);
|
||||||
|
if (encArr !== null) {
|
||||||
|
if (pStart < oldPos) {
|
||||||
|
pArray.push(text.slice(pStart, oldPos));
|
||||||
|
}
|
||||||
|
pArray.push([tag, encArr[0], encArr[1]]);
|
||||||
|
pStart = text.iter + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text.moveForward();
|
text.moveForward();
|
||||||
|
|
|
@ -3,6 +3,34 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gets a descriptive text of the domain of the link
|
||||||
|
* Example:
|
||||||
|
* https://www.youtube.com/watch?v=G8APgeFfkAk returns 'youtube'
|
||||||
|
* http://www.google.at returns 'google.at'
|
||||||
|
* (www. and .com are split)
|
||||||
|
*/
|
||||||
|
function getLinkDesc(link) {
|
||||||
|
let domainStart = link.indexOf('://') + 3;
|
||||||
|
if (domainStart < 3) {
|
||||||
|
domainStart = 0;
|
||||||
|
}
|
||||||
|
if (link.startsWith('www.', domainStart)) {
|
||||||
|
domainStart += 4;
|
||||||
|
}
|
||||||
|
let domainEnd = link.indexOf('/', domainStart);
|
||||||
|
if (domainEnd === -1) {
|
||||||
|
domainEnd = link.length;
|
||||||
|
}
|
||||||
|
if (link.endsWith('.com', domainEnd)) {
|
||||||
|
domainEnd -= 4;
|
||||||
|
}
|
||||||
|
if (domainEnd <= domainStart) {
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
return link.slice(domainStart, domainEnd);
|
||||||
|
}
|
||||||
|
|
||||||
const MarkdownParagraph = ({ pArray }) => pArray.map((part) => {
|
const MarkdownParagraph = ({ pArray }) => pArray.map((part) => {
|
||||||
if (!Array.isArray(part)) {
|
if (!Array.isArray(part)) {
|
||||||
return part;
|
return part;
|
||||||
|
@ -35,19 +63,32 @@ const MarkdownParagraph = ({ pArray }) => pArray.map((part) => {
|
||||||
<MarkdownParagraph pArray={part[1]} />
|
<MarkdownParagraph pArray={part[1]} />
|
||||||
</u>
|
</u>
|
||||||
);
|
);
|
||||||
case 'l':
|
case 'l': {
|
||||||
|
let title = getLinkDesc(part[2]);
|
||||||
|
if (part[1]) {
|
||||||
|
title += ` | ${part[1]}`;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<a href={part[2]}>
|
<a href={part[2]}>
|
||||||
{part[1]}
|
{title}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
case 'img': {
|
||||||
|
let title = getLinkDesc(part[2]);
|
||||||
|
if (part[1]) {
|
||||||
|
title += ` | ${part[1]}`;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<img src={part[2]} title={part[1] || title} alt={title} />
|
||||||
|
);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Markdown = ({ mdArray }) => {
|
const Markdown = ({ mdArray }) => mdArray.map((part) => {
|
||||||
return mdArray.map((part) => {
|
|
||||||
const type = part[0];
|
const type = part[0];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
/* Heading */
|
/* Heading */
|
||||||
|
@ -127,7 +168,7 @@ const Markdown = ({ mdArray }) => {
|
||||||
default:
|
default:
|
||||||
return part[0];
|
return part[0];
|
||||||
}
|
}
|
||||||
})};
|
});
|
||||||
|
|
||||||
const MarkdownArticle = ({ mdArray }) => (
|
const MarkdownArticle = ({ mdArray }) => (
|
||||||
<article>
|
<article>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
# Markdown parser testing
|
# Markdown parser testing
|
||||||
|
|
||||||
Code to test markdown parsing, run `npx webpack` to build and open index.html
|
Code to test markdown parsing, run `npx webpack` to build and open index.html
|
||||||
|
|
||||||
|
No npm install in this folder neccessary, it takes the packages from the parent project
|
||||||
|
|
|
@ -22,7 +22,7 @@ var babelPlugins = [
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'script',
|
name: 'script',
|
||||||
target: 'web',
|
target: 'web',
|
||||||
mode: 'production',
|
mode: 'development',
|
||||||
|
|
||||||
entry: [ path.resolve(__dirname, './mdtest.js') ],
|
entry: [ path.resolve(__dirname, './mdtest.js') ],
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user