Files
Luma-Parser/ui/javascript/markdown2/parser.mjs
T
2026-06-29 15:56:30 +02:00

368 lines
10 KiB
JavaScript

import * as $dict from "../gleam_stdlib/gleam/dict.mjs";
import * as $stdlib$dict from "../gleam_stdlib/gleam/dict.mjs";
import * as $int from "../gleam_stdlib/gleam/int.mjs";
import * as $list from "../gleam_stdlib/gleam/list.mjs";
import * as $result from "../gleam_stdlib/gleam/result.mjs";
import * as $string from "../gleam_stdlib/gleam/string.mjs";
import * as $definition from "./definition.mjs";
import {
Ok,
toList,
Empty as $Empty,
NonEmpty as $NonEmpty,
CustomType as $CustomType,
bitArraySlice,
bitArraySliceToInt,
BitArray as $BitArray,
List as $List,
UtfCodepoint as $UtfCodepoint,
} from "./gleam.mjs";
import * as $mode from "./mode.mjs";
function whatsthat(mod) {
let modes = $dict.from_list(
toList([
[
"!",
[
new $mode.Marking(),
(var0) => { return new $definition.Marking(var0); },
],
],
[
"@",
[new $mode.Truth(), (var0) => { return new $definition.Truth(var0); }],
],
[
">",
[new $mode.Quote(), (var0) => { return new $definition.Quote(var0); }],
],
[
"#",
[
new $mode.Hirachy(),
(var0) => { return new $definition.Hirachy(var0); },
],
],
]),
);
let $ = $string.pop_grapheme(mod);
if ($ instanceof Ok) {
let prefix = $[0][0];
let rest = $[0][1];
let $1 = $dict.get(modes, prefix);
if ($1 instanceof Ok) {
let m = $1[0][0];
let make_definition = $1[0][1];
if (rest === "-") {
return new $definition.Pop(m);
} else {
let _block;
let _pipe = $int.parse(rest);
_block = $result.unwrap(_pipe, 1);
let value = _block;
return new $definition.Push(make_definition(value));
}
} else {
return new $definition.Text(mod);
}
} else {
return new $definition.Text(mod);
}
}
function parse(modificators) {
let _pipe = modificators;
let _pipe$1 = $string.replace(_pipe, "#", " |#");
let _pipe$2 = $string.replace(_pipe$1, "@", " |@");
let _pipe$3 = $string.replace(_pipe$2, "!", " |!");
let _pipe$4 = $string.replace(_pipe$3, ">", " |>");
let _pipe$5 = $string.split(_pipe$4, " |");
let _pipe$6 = $list.flat_map(
_pipe$5,
(block) => {
let $ = (($string.starts_with(block, "#") || $string.starts_with(
block,
"@",
)) || $string.starts_with(block, "!")) || $string.starts_with(block, ">");
if ($) {
let $1 = $string.split_once(block, " ");
if ($1 instanceof Ok) {
let tag = $1[0][0];
let rest = $1[0][1];
return toList([tag, rest]);
} else {
return toList([block]);
}
} else {
return toList([block]);
}
},
);
let _pipe$7 = $list.map(_pipe$6, $string.trim);
return $list.filter(_pipe$7, (x) => { return x !== ""; });
}
export function handler(line) {
let result = parse(line);
let result$1 = echo(
$list.map(result, whatsthat),
undefined,
"src/parser.gleam",
10,
);
return new $definition.Line(result$1);
}
function echo(value, message, file, line) {
const grey = "\u001b[90m";
const reset_color = "\u001b[39m";
const file_line = `${file}:${line}`;
const inspector = new Echo$Inspector();
const string_value = inspector.inspect(value);
const string_message = message === undefined ? "" : " " + message;
if (globalThis.process?.stderr?.write) {
// If we're in Node.js, use `stderr`
const string = `${grey}${file_line}${reset_color}${string_message}\n${string_value}\n`;
globalThis.process.stderr.write(string);
} else if (globalThis.Deno) {
// If we're in Deno, use `stderr`
const string = `${grey}${file_line}${reset_color}${string_message}\n${string_value}\n`;
globalThis.Deno.stderr.writeSync(new TextEncoder().encode(string));
} else {
// Otherwise, use `console.log`
// The browser's console.log doesn't support ansi escape codes
const string = `${file_line}${string_message}\n${string_value}`;
globalThis.console.log(string);
}
return value;
}
class Echo$Inspector {
#references = new globalThis.Set();
#isDict(value) {
try {
// We can only check if an object is a stdlib Dict if it is one of the
// project's dependencies.
// We import the public gleam/dict module, so to check if something is a
// dict we compare the `constructor` field on the object with that of a
// new dict.
const empty_dict = $stdlib$dict.new$();
const dict_class = empty_dict.constructor;
return value instanceof dict_class;
} catch {
// If stdlib is not one of the project's dependencies then `$stdlib$dict`
// will not have been imported and the check will throw an exception meaning
// we can't check if something is actually a `Dict`.
return false;
}
}
#float(float) {
const string = float.toString().replace("+", "");
if (string.indexOf(".") >= 0) {
return string;
} else {
const index = string.indexOf("e");
if (index >= 0) {
return string.slice(0, index) + ".0" + string.slice(index);
} else {
return string + ".0";
}
}
}
inspect(v) {
const t = typeof v;
if (v === true) return "True";
if (v === false) return "False";
if (v === null) return "//js(null)";
if (v === undefined) return "Nil";
if (t === "string") return this.#string(v);
if (t === "bigint" || globalThis.Number.isInteger(v)) return v.toString();
if (t === "number") return this.#float(v);
if (v instanceof $UtfCodepoint) return this.#utfCodepoint(v);
if (v instanceof $BitArray) return this.#bit_array(v);
if (v instanceof globalThis.RegExp) return `//js(${v})`;
if (v instanceof globalThis.Date) return `//js(Date("${v.toISOString()}"))`;
if (v instanceof globalThis.Error) return `//js(${v.toString()})`;
if (v instanceof globalThis.Function) {
const args = [];
for (const i of globalThis.Array(v.length).keys())
args.push(globalThis.String.fromCharCode(i + 97));
return `//fn(${args.join(", ")}) { ... }`;
}
if (this.#references.size === this.#references.add(v).size) {
return "//js(circular reference)";
}
let printed;
if (globalThis.Array.isArray(v)) {
printed = `#(${v.map((v) => this.inspect(v)).join(", ")})`;
} else if (v instanceof $List) {
printed = this.#list(v);
} else if (v instanceof $CustomType) {
printed = this.#customType(v);
} else if (this.#isDict(v)) {
printed = this.#dict(v);
} else if (v instanceof Set) {
return `//js(Set(${[...v].map((v) => this.inspect(v)).join(", ")}))`;
} else {
printed = this.#object(v);
}
this.#references.delete(v);
return printed;
}
#object(v) {
const name =
globalThis.Object.getPrototypeOf(v)?.constructor?.name || "Object";
const props = [];
for (const k of globalThis.Object.keys(v)) {
props.push(`${this.inspect(k)}: ${this.inspect(v[k])}`);
}
const body = props.length ? " " + props.join(", ") + " " : "";
const head = name === "Object" ? "" : name + " ";
return `//js(${head}{${body}})`;
}
#dict(map) {
let body = "dict.from_list([";
let first = true;
let key_value_pairs = $stdlib$dict.fold(map, [], (pairs, key, value) => {
pairs.push([key, value]);
return pairs;
});
key_value_pairs.sort();
key_value_pairs.forEach(([key, value]) => {
if (!first) body = body + ", ";
body = body + "#(" + this.inspect(key) + ", " + this.inspect(value) + ")";
first = false;
});
return body + "])";
}
#customType(record) {
const props = globalThis.Object.keys(record)
.map((label) => {
const value = this.inspect(record[label]);
return isNaN(parseInt(label)) ? `${label}: ${value}` : value;
})
.join(", ");
return props
? `${record.constructor.name}(${props})`
: record.constructor.name;
}
#list(list) {
if (list instanceof $Empty) {
return "[]";
}
let char_out = 'charlist.from_string("';
let list_out = "[";
let current = list;
while (current instanceof $NonEmpty) {
let element = current.head;
current = current.tail;
if (list_out !== "[") {
list_out += ", ";
}
list_out += this.inspect(element);
if (char_out) {
if (
globalThis.Number.isInteger(element) &&
element >= 32 &&
element <= 126
) {
char_out += globalThis.String.fromCharCode(element);
} else {
char_out = null;
}
}
}
if (char_out) {
return char_out + '")';
} else {
return list_out + "]";
}
}
#string(str) {
let new_str = '"';
for (let i = 0; i < str.length; i++) {
const char = str[i];
switch (char) {
case "\n":
new_str += "\\n";
break;
case "\r":
new_str += "\\r";
break;
case "\t":
new_str += "\\t";
break;
case "\f":
new_str += "\\f";
break;
case "\\":
new_str += "\\\\";
break;
case '"':
new_str += '\\"';
break;
default:
if (char < " " || (char > "~" && char < "\u{00A0}")) {
new_str +=
"\\u{" +
char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0") +
"}";
} else {
new_str += char;
}
}
}
new_str += '"';
return new_str;
}
#utfCodepoint(codepoint) {
return `//utfcodepoint(${globalThis.String.fromCodePoint(codepoint.value)})`;
}
#bit_array(bits) {
if (bits.bitSize === 0) {
return "<<>>";
}
let acc = "<<";
for (let i = 0; i < bits.byteSize - 1; i++) {
acc += bits.byteAt(i).toString();
acc += ", ";
}
if (bits.byteSize * 8 === bits.bitSize) {
acc += bits.byteAt(bits.byteSize - 1).toString();
} else {
const trailingBitsCount = bits.bitSize % 8;
acc += bits.byteAt(bits.byteSize - 1) >> (8 - trailingBitsCount);
acc += `:size(${trailingBitsCount})`;
}
acc += ">>";
return acc;
}
}