Refactor trimming utility
This commit is contained in:
parent
5208496124
commit
631acc8122
7
src/components/Code.astro
Normal file
7
src/components/Code.astro
Normal 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>
|
133
src/components/utils.test.ts
Normal file
133
src/components/utils.test.ts
Normal 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",
|
||||||
|
]);
|
||||||
|
});
|
@ -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}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
}
|
}
|
||||||
```
|
`} />
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user