Published
Edited
Jun 27, 2022
1 star
Insert cell
Insert cell
P = require("parsimmon")
Insert cell
Insert cell
Insert cell
{
// apply a function to a match
const numberParser = P.regex(/[0-9]/).map((match) => Number(match));

return numberParser.parse("2");
}
Insert cell
{
// use an ordered sequence of matches
const sequence = P.seq(P.string("("), P.regex(/\w+/), P.string(")"));

return sequence.parse("(word)");
}
Insert cell
{
// compose matches
const sequence = P.seq(P.string("("), P.regex(/\w+/), P.string(")"));

const advancedSequence = P.seq(P.string("{"), sequence, P.string("}"));

return advancedSequence.parse("{(word)}");
}
Insert cell
{
// multiple viable matches
const numericMonthParser = P.regex(/[0-9]+/)
.map(Number)
.chain((match) => {
if (0 < match && match <= 12) {
return P.succeed(match);
}
return P.fail("Not a valid month");
});

const months = {
january: 1,
february: 2,
march: 3,
april: 4,
may: 5,
june: 6,
july: 7,
august: 8,
september: 9,
october: 10,
november: 11,
december: 12
};

const writtenMonthParser = P.letters.chain((word) => {
const number = months[word.toLowerCase()];
return number ? P.succeed(number) : P.fail("Not a valid month");
});

const monthParser = P.alt(numericMonthParser, writtenMonthParser);

return {
numericExample: monthParser.parse("1"),
writtenExample: monthParser.parse("October"),
failureExample: monthParser.parse("Invalid input")
};
}
Insert cell
Insert cell
language = {
const textParser = (r) =>
P.regex(/[A-Za-z'\-":!?,.]+/).map((value) => ({
type: "text",
value
}));

const boldParser = (r) =>
P.seqObj(P.string("**"), ["children", r.value], P.string("**")).map(
({ children }) => ({
type: "bold",
children
})
);

const italicParser = (r) =>
P.seqObj(P.string("_"), ["children", r.value], P.string("_")).map(
({ children }) => ({
type: "italic",
children
})
);

const whitespaceParser = (r) => P.regex(/ +/).result({ type: "whitespace" });

const newlineParser = (r) => P.regex(/\n/).result({ type: "newline" });

const urlRegex = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/;

const markdownUrlParser = (r) =>
P.seqObj(
P.string("["),
["children", r.phrasing.many()],
P.string("]("),
["href", P.regex(urlRegex)],
P.string(")")
).map(({ children, href }) => ({
type: "url",
children,
href
}));

const plainURLParser = P.regex(urlRegex).map((result) => ({
type: "url",
children: [{ type: "text", value: result }],
href: result
}));

const urlParser = (r) => P.alt(markdownUrlParser(r), plainURLParser);

const language = P.createLanguage({
phrasing: (r) => P.alt(r.whitespace, r.bold, r.italic, r.text),
whitespace: whitespaceParser,
newline: newlineParser,
bold: boldParser,
italic: italicParser,
text: textParser,
url: urlParser,
value: (r) => P.alt(r.newline, r.url, r.phrasing).many()
});

return language;
}
Insert cell
language.value.parse(
`www.observablehq.com [observable **and** more](www.observablehq.com)`
)
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more