Refactor trimming utility

This commit is contained in:
Araozu 2024-07-05 09:09:49 -05:00
parent 5208496124
commit 631acc8122
4 changed files with 200 additions and 4 deletions

View File

@ -0,0 +1,7 @@
---
import { leftTrimDedent } from "./utils";
const { thpcode } = Astro.props;
---
<pre class="language-thp" data-language="thp"><code class="language-thp">{leftTrimDedent(thpcode).join("\n")}</code></pre>

View File

@ -0,0 +1,133 @@
import { expect, test } from 'vitest'
import { leftTrimDedent } from "./utils"
test("should trim empty string", () => {
const input = ``;
expect(leftTrimDedent(input)).toEqual([""]);
})
test("should work on a single line", () => {
const input = `hello`
expect(leftTrimDedent(input)).toEqual([
"hello"
]);
})
test("should trim a single line", () => {
const input = ` hello`
expect(leftTrimDedent(input)).toEqual([
"hello"
]);
})
test("should trim multiple lines", () => {
const input = ` hello\n world`
expect(leftTrimDedent(input)).toEqual([
"hello",
"world"
]);
})
test("should trim multiple lines without indentation", () => {
const input = `hello\nworld`
expect(leftTrimDedent(input)).toEqual([
"hello",
"world"
]);
})
test("should consume only whitespace", () => {
const input = ` hello\nworld`;
try {
const res = leftTrimDedent(input);
expect(res).not.toEqual([
"hello",
"rld",
]);
} catch (e) {
expect(e).toBeInstanceOf(Error);
expect(e).toHaveProperty("message", "Invalid indentation while trimming: Expected 2 spaces, got 0");
}
})
test("should preserve deeper indentation", () => {
const input = ` hello\n world`
expect(leftTrimDedent(input)).toEqual([
"hello",
" world",
]);
})
test("should ignore empty lines", () => {
const input = ` hello\n\n world`
expect(leftTrimDedent(input)).toEqual([
"hello",
"",
"world",
]);
})
test("should ignore lines with only whitespace", () => {
const input = ` hello\n \n \n world`
expect(leftTrimDedent(input)).toEqual([
"hello",
"",
" ",
"world",
]);
})
test("should trim multiple without indentation", () => {
const input = `hello\nworld\n!`
expect(leftTrimDedent(input)).toEqual([
"hello",
"world",
"!",
]);
})
test("should ignore empty first line", () => {
const input = `
hello
world`;
expect(leftTrimDedent(input)).toEqual([
"hello",
"world",
]);
})
test("should ignore empty first line 2", () => {
const input = `
hello
world`;
expect(leftTrimDedent(input)).toEqual([
"hello",
"",
"world",
]);
})
test("should ignore empty last line", () => {
const input = `
hello
world
`;
expect(leftTrimDedent(input)).toEqual([
"hello",
"world",
]);
});

View File

@ -45,7 +45,7 @@ export function trimAndDedent(input: string): Array<string> {
let currentIndentation = 0; let currentIndentation = 0;
for (const c of characters) { for (const c of characters) {
if (c === " ") { currentIndentation += 1 } if (c === " ") { currentIndentation += 1 }
else {break;} else { break; }
} }
if (currentIndentation < indentationLevel) { if (currentIndentation < indentationLevel) {
throw new Error("Invalid indentation while parsing THP code: " + lines[i]); throw new Error("Invalid indentation while parsing THP code: " + lines[i]);
@ -67,4 +67,58 @@ export function trimAndDedent(input: string): Array<string> {
} }
return lines; return lines;
} }
export function leftTrimDedent(input: string): Array<string> {
let lines = input.split("\n");
let output: Array<string> = [];
// Ignore first line
if (lines[0] === "" && lines.length > 1) {
lines = lines.slice(1);
}
// Get indentation level of the first line
let indentationLevel = 0;
for (const char of lines[0]!) {
if (char === " ") {
indentationLevel += 1;
} else {
break;
}
}
for (const line of lines) {
// Ignore empty lines
if (line === "") {
output.push("");
continue;
}
output.push(trimWhitespace(line, indentationLevel));
}
if (output.length > 1 && output[output.length - 1] === "") {
output = output.slice(0, -1);
}
return output;
}
function trimWhitespace(input: string, count: number): string {
let indentCount = 0;
for (const char of input) {
if (char === " ") {
indentCount += 1;
} else {
break;
}
}
if (indentCount >= count || indentCount == input.length) {
return input.slice(count);
} else {
throw new Error(`Invalid indentation while trimming: Expected ${count} spaces, got ${indentCount}`);
}
}

View File

@ -2,6 +2,7 @@
layout: ../../../layouts/DocsLayout.astro layout: ../../../layouts/DocsLayout.astro
title: Introduction title: Introduction
--- ---
import Code from "../../../components/Code.astro"
# THP templating # THP templating
@ -71,7 +72,8 @@ fun Button(String name) -> Html {
It is very similar to React. The HTML is inside the THP code, not the other It is very similar to React. The HTML is inside the THP code, not the other
way around, so you can have arbitrary logic in the component. way around, so you can have arbitrary logic in the component.
```thp
<Code thpcode={`
fun User(String name) { fun User(String name) {
// Get info from the database // Get info from the database
val user = try Model::get_user(name) val user = try Model::get_user(name)
@ -96,7 +98,7 @@ fun TransactionItem(Transaction t) {
{t.date} - {t.name} ({t.price}) {t.date} - {t.name} ({t.price})
</li> </li>
} }
``` `} />